跳到內容

每條游來游去的小魚,都是正在瀏覽這一頁的訪客,有一條是你自己 ( ´ ▽ ` )ノ 覺得干擾閱讀的話,可以把小魚關掉。

當機卡片

card

致敬 Windows XP 卡住時,視窗移動疊影 BUG

名稱描述
Pointer 事件偵測滑鼠或觸控點移動、點擊、懸停等等事件,取得座標、目標等等資訊
Canvas 2D API基礎的 2D 繪圖 API,可以高效繪製比 DOM 更複雜的圖形
CSS 動畫基於 CSS transition 和 animation 實現
DOM to Image將 DOM 元素轉換為圖片的技術,基於 SVG foreignObject 實現

拉拉看視窗吧 ( ´ ▽ ` )ノ

Hello, Windows XP!

嘗試拖動這個視窗

<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>

將 DOM 轉換成圖片,然後不斷繪製圖片至 canvas。

原本實作方式想說同 btn-ninja 一樣,使用 v-for 產生多個 default slot 內容,但是性能實在過於慘烈,所以改用 canvas 實現。

想是這麼想,這裡會遇到難題,要怎麼將 DOM 畫到 canvas 上?ლ(╹ε╹ლ)」

html2canvas 與 dom-to-image 都不太理想,後來發現 vfx.js 這個套件內有完整實作。

於是我就直接複製過來,並稍微修改成符合我需求的版本惹。◝( •ω• )◟

interface Props {
draggable?: boolean;
throttle?: number;
}
interface Expose {
clearArtifacts: () => void;
}
interface SlotScope {
isDragging: boolean;
/**
* 用於綁定拖動把手
* @param el - 要綁定的元素
*/
bindHandle: (el: any) => void;
}
interface Slots {
default?: (params: SlotScope) => unknown;
}