Render Glitch Card card
A tribute to the Windows XP window-dragging ghost trail bug.
Usage Examples
Basic Usage
Try dragging the window! ( ´ ▽ ` )ノ
Hello, Windows XP!
Try dragging this window
View example source code
vue
<template>
<div class="w-full flex flex-col gap-4 py-4">
<div class="flex items-center justify-center py-[8vh]">
<card-render-glitch
v-slot="{ bindHandle }"
:draggable
class="window z-50 overflow-hidden border rounded-xl shadow-xl"
>
<div
:ref="bindHandle"
class="handle w-full flex items-center px-4"
:class="draggable ? 'cursor-move' : 'cursor-no-drop'"
>
<div class="flex-1 select-none text-center text-sm font-medium">
Hello, Windows XP!
</div>
<button class="mb-1 text-2xl">
×
</button>
</div>
<div class="flex flex-col gap-2 p-8 px-12">
<base-checkbox
v-model="draggable"
:label="t('enableDrag')"
/>
<p class="leading-relaxed">
{{ t('tryDrag') }}
</p>
</div>
</card-render-glitch>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseCheckbox from '../../base-checkbox.vue'
import CardRenderGlitch from '../card-render-glitch.vue'
const draggable = ref(true)
const { t } = useI18n()
</script>
<style lang="sass" scoped>
:deep(.window)
background: light-dark(#FFF, #1e1e1e)
border-color: light-dark(#d0d0d0, #888)
color: light-dark(#374151, #d1d5db)
.handle
background: light-dark(#f3f4f6, #111827)
color: light-dark(#1f2937, #d1d5db)
</style>How It Works
Converts the DOM into an image, then continuously draws the image onto a canvas.
How to convert DOM to Image?
The original implementation idea was to use v-for to generate multiple default slot contents like btn-ninja, but the performance was terrible, so canvas was used instead.
The challenge was: "How to draw DOM onto a canvas? ლ(╹ε╹ლ)"
Both html2canvas and dom-to-image were not ideal. Later, a complete implementation was found in the vfx.js library.
So I copied it over and slightly modified it to fit my needs. ◝( •ω• )◟
Source Code
API
Props
interface Props {
draggable?: boolean;
throttle?: number;
}Methods
interface Expose {
clearArtifacts: () => void;
}Slots
interface SlotScope {
isDragging: boolean;
/**
* 用於綁定拖動把手
* @param el - 要綁定的元素
*/
bindHandle: (el: any) => void;
}
interface Slots {
default?: (params: SlotScope) => unknown;
}