每條游來游去的小魚,都是正在瀏覽這一頁的訪客,有一條是你自己 ( ´ ▽ ` )ノ 覺得干擾閱讀的話,可以把小魚關掉。
落雪
bg讓網頁飄雪的背景效果,還會積雪喔。( ´ ▽ ` )ノ
| 名稱 | 描述 |
|---|---|
| Babylon.js | 3D 引擎 |
| 粒子系統 | 產生大量小物件的系統,常用於模擬煙霧、火焰、雨雪等效果 |
| OffscreenCanvas | 由外部執行緒計算 Canvas 繪製,不阻塞主執行緒 |
| Web Worker | 在背景執行緒執行腳本,避免阻塞主執行緒的 UI 操作 |
| Vue Directive | 自定義 Vue 指令,用於封裝 DOM 操作邏輯和重複行為 |
| 物理模擬 | 模擬真實世界物理現象,如重力、碰撞、速度等物理效果 |
使用 v-bg-static 指令可以讓指定物體積雪。
還可以調整雪片圖片與大小。
<template> <div class="w-full flex items-center justify-center py-10"> <div class="grid grid-cols-4 gap-10"> <base-checkbox v-model="enable" v-bg-static :label="t('startSnow')" class="col-span-4 border border-gray-200 rounded-full p-4 px-6 sm:col-span-3" />
<base-btn v-bg-static :label="t('sweep')" class="col-span-4 border-gray-200 !rounded-full sm:col-span-1" @click="sweep()" />
<base-input :label="t('snowflakeImage')" class="col-span-2" > <div v-bg-static class="border rounded" > <input type="file" accept="image/*" class="px-2 py-1" @change="handleImageChange" > </div> </base-input>
<base-input v-model="options.size" :label="`${t('particleSize')}: ${options.size}`" type="range" :min="1" :max="20" class="col-span-2" /> </div>
<bg-snow ref="bgRef" class="fixed left-0 top-0 z-[100] h-full w-full" :class="{ 'opacity-0': !enable }" :image-src="imgUrl" :size="options.size" /> </div></template>
<script setup lang="ts">import { useObjectUrl } from '@vueuse/core'import { onUnmounted, ref, useTemplateRef, watch } from 'vue'import { useI18n } from 'vue-i18n'import { useSiteDark } from '../../../composables/use-site-dark'import BaseBtn from '../../base-btn.vue'import BaseCheckbox from '../../base-checkbox.vue'import BaseInput from '../../base-input.vue'import BgSnow from '../bg-snow.vue'import { vBgStatic } from '../v-bg-static'
const { t } = useI18n()
const enable = ref(false)
const imgFile = ref<File>()function handleImageChange(event: Event) { const file = (event.target as HTMLInputElement).files?.[0] imgFile.value = file}const imgUrl = useObjectUrl(imgFile)
const bgRef = useTemplateRef('bgRef')const options = ref({ size: 8,})function sweep() { bgRef.value?.sweep()}
const isDark = useSiteDark()
const oriValue = isDark.value
watch(enable, (value) => { isDark.value = value})
onUnmounted(() => { isDark.value = oriValue})</script>下雪動畫以 babylon.js 粒子系統實作,積雪效果則是偵測 v-bg-static 標記的 DOM 是否碰撞
但雪的數量非常多,若直接在主執行緒計算,龐大的計算量會導致畫面卡頓、不流暢。
這裡直接用上 Offscreen Canvas 這個有趣的小技巧!( •̀ ω •́ )✧
這個技術可以讓整個 Canvas 繪製都交給 Web Worker 處理,也就是說包含費時的計算任務在內,所有計算都不在主執行續執行,就不用擔心畫面卡頓了。(/≧▽≦)/
大家查看原始碼時,可能會發現我用了名為 Comlink 的套件,這個套件可以大幅簡化 Web Worker 與主執行續之間怎麼傳遞訊息。( ´ ▽ ` )ノ
不然原本要用 postMessage 傳遞訊息,寫起來真滴麻煩。⎝(・ω´・⎝)
Methods
Section titled “Methods”interface Expose { /** 清除積雪 */ sweep: () => void;}