每條游來游去的小魚,都是正在瀏覽這一頁的訪客,有一條是你自己 ( ´ ▽ ` )ノ 覺得干擾閱讀的話,可以把小魚關掉。
特效轉場
transition效果酷炫、風格強烈的 Transition 元件!◝( •ω• )◟
| 名稱 | 描述 |
|---|---|
| Anime.js | 輕量級 JavaScript 動畫函式庫 |
| JS 動畫 | 基於 JavaScript 實現的動畫,達成更複雜、精準的動畫控制,常見套件有 GSAP、anime.js 等 |
| SVG Filter | SVG 濾鏡效果,例如:模糊、扭曲、顏色調整等等 |
| Vue Transition | 內建元件,可以處理單個項目的進出動畫 |
| SVG feDisplacementMap | 依位移圖的色值偏移取樣來源像素,可做出扭曲、凹陷、波動等效果 |
| SVG feColorMatrix | 以 4×5 矩陣重算每個像素的 RGBA,可調色、轉灰階或逐格插值動畫 |
用法與 Vue 內建的 Transition 元件相同。
(點擊後開始轉場)
WAVE
CYBERPSYCHOSIS
MELT
GLITCH
ERODE
<template> <div class="w-full flex flex-col gap-4 example-wrap"> <div class="flex flex-col items-center justify-center gap-3"> <div v-for="item in list" :key="item.name" class="item h-[5rem] w-full flex items-center justify-center" @click="item.visible = !item.visible" > <transition-special-effects :enter="item.name" :leave="item.name" > <div v-if="item.visible" class="px-8 py-2" :class="item.class" > {{ item.name.toUpperCase() }} </div> </transition-special-effects> </div> </div> </div></template>
<script setup lang="ts">import type { TransitionName } from '../type'import { ref } from 'vue'import TransitionSpecialEffects from '../transition-special-effects.vue'
const list = ref<Array<{ visible: boolean; name: `${TransitionName}`; class: string;}>>([{ visible: true, name: 'wave', class: 'bg-blue-200 text-blue-900 text-2xl font-bold rounded-full',}, { visible: true, name: 'cyberpsychosis', class: 'bg-gray-200 text-gray-900 text-2xl font-bold',}, { visible: true, name: 'melt', class: 'text-gray-400 dark:text-gray-500 border-2 border-gray-200 text-3xl rounded-xl font-bold',}, { visible: true, name: 'glitch', class: 'text-red-800 border-dashed border border-red-800 text-2xl font-bold',}, { visible: true, name: 'erode', class: 'bg-[#222] text-white text-2xl font-black tracking-widest',}])</script>
<style scoped lang="sass">.item cursor: pointer transition-duration: 0.5s</style>可以分別指定 enter 與 leave 特效。
進入特效
離開特效

鱈魚 Codfish
困擾買不到 IP69K 等級的防水電腦 ( ´•̥̥̥ ω •̥̥̥` )
<!-- #region main-code --><template> <div class="example-wrap w-full flex flex-col gap-4"> <div class="example-ctrl flex flex-col gap-4"> <div class="flex items-center gap-1 px-4"> <div class="w-20"> {{ t('進入特效') }} </div>
<div class="flex-1 border rounded"> <base-select v-model="enterName" :options class="w-full" /> </div> </div>
<div class="flex items-center gap-1 px-4"> <div class="w-20"> {{ t('離開特效') }} </div>
<div class="flex-1 border rounded"> <base-select v-model="leaveName" :options class="w-full" /> </div> </div>
<base-checkbox v-model="visible" :label="t('顯示')" class="px-4" /> </div>
<div class="h-[50vh] flex cursor-pointer items-center justify-center" @click="visible = !visible" > <transition-special-effects :enter="enterName" :leave="leaveName" > <div v-if="visible" class="flex flex-col items-center gap-4" > <img src="/low/profile.webp" alt="" class="mb-4 h-60 w-60 overflow-hidden border-4 border-white rounded-full shadow-xl" >
<div class="text-xl font-bold"> {{ t('鱈魚 Codfish') }} </div>
<div> {{ t('困擾買不到 IP69K 等級的防水電腦') }} </div> </div> </transition-special-effects> </div> </div></template>
<script setup lang="ts">import { ref } from 'vue'import { useI18n } from 'vue-i18n'import BaseCheckbox from '../../base-checkbox.vue'import BaseSelect from '../../base-select.vue'import TransitionSpecialEffects from '../transition-special-effects.vue'import { TransitionName } from '../type'
const { t } = useI18n()
const visible = ref(true)const enterName = ref<`${TransitionName}`>('wave')const leaveName = ref<`${TransitionName}`>('wave')
const options = Object.values(TransitionName)</script><!-- #endregion main-code -->
<i18n lang="json">{ "zh-hant": { "進入特效": "進入特效", "離開特效": "離開特效", "顯示": "顯示", "鱈魚 Codfish": "鱈魚 Codfish", "困擾買不到 IP69K 等級的防水電腦": "困擾買不到 IP69K 等級的防水電腦 ( ´•̥̥̥ ω •̥̥̥` )" }, "en": { "進入特效": "Enter Effect", "離開特效": "Leave Effect", "顯示": "Show", "鱈魚 Codfish": "Codfish", "困擾買不到 IP69K 等級的防水電腦": "Troubled by not being able to buy an IP69K waterproof computer ( ´•̥̥̥ ω •̥̥̥` )" }}</i18n>這類特殊效果已經完全超出 CSS 範疇。
一開始往 HTML to Canvas 方向研究,但是 HTML 轉換成 Canvas 會有很多誤差,成果實在不忍直視。(́⊙◞౪◟⊙‵)
最後發現 SVG Filter 最適合,因為 SVG Filter 可以直接對 HTML 元素套用濾鏡效果。
剛好趁這個機會好好研究 SVG Filter,相當複雜,但是真的很有趣。(*´∀`)~♥
實作概念為:
- 將 SVG Filter 內容獨立為 Vue 元件,使用
v-bind綁定參數,配合animejs產生動畫。 - 產生唯一 ID,綁定至目標元素
style,產生濾鏡效果。
interface Props { appear?: boolean; enter?: EnterParams; leave?: LeaveParams;}const emit = defineEmits<{ (e: 'init'): void; (e: 'beforeEnter'): void; (e: 'afterEnter'): void; (e: 'beforeLeave'): void; (e: 'afterLeave'): void;}>()defineSlots<{ default?: () => unknown;}>()