現在讓我們用更多範例讓使用者更了解「逐字轉場」元件吧。ヽ(●`∀´●)ノ
展示如何自定義切分文字。
src\components\text-characters-transition\examples\custom-splitter.vue
<template>
<div class="flex flex-col gap-4 w-full border border-gray-300 p-6">
<label class=" flex items-center border p-4 rounded">
<input
v-model="visible"
type="checkbox"
>
<span class="ml-2">
顯示文字
</span>
</label>
<div class="flex flex-col gap-2">
<text-characters-transition
:visible="visible"
label="一隻熱愛程式的魚,但是沒有手指可以打鍵盤,更買不到能在水裡用的電腦。"
:splitter="/(,)/"
/>
<text-characters-transition
:visible="visible"
:label="[
'鱈魚', '是一種', '很油', '很油', '的', '肥魚'
]"
:enter="(i) => ({ delay: i * 200 })"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import TextCharactersTransition from '../text-characters-transition.vue';
const visible = ref(false);
</script>
在文件中引入範例。
docs\components\text-characters-transition\index.md
...
<script setup>
import BasicUsage from '../../../src/components/text-characters-transition/examples/basic-usage.vue'
import CustomSplitter from '../../../src/components/text-characters-transition/examples/custom-splitter.vue'
</script>
...
### 切分文字
可以自行設定文字分割邏輯或是提供分好的文字。
<custom-splitter/>
::: details 查看範例原始碼
<<< ../../../src/components/text-characters-transition/examples/custom-splitter.vue
:::
...
新增切分文字範例。◝( •ω• )◟
可以切換不同過場類型。
不過目前只有淡入淡出,讓我們再多新增幾個動畫吧。
src\components\text-characters-transition\transition-provider.ts
...
export enum TransitionName {
...
BLUR = 'blur',
CLIP_RIGHT = 'clip-right',
}
export const transitionProvider: Record<...> = {
...
[TransitionName.BLUR]: {
enter: (i) => ({
opacity: 1,
filter: ['blur(10px)', 'blur(0px)'],
delay: i * 100,
easing: 'easeOutCirc',
}),
leave: (i) => ({
opacity: 0,
filter: ['blur(0px)', 'blur(10px)'],
delay: i * 100,
easing: 'easeInCirc',
}),
},
[TransitionName.CLIP_RIGHT]: {
enter: (i) => ({
clipPath: [
'polygon(0 0, 0 0, 0 100%, 0% 100%)',
'polygon(0 0, 100% 0, 100% 100%, 0% 100%)',
],
delay: i * 10,
easing: 'easeInOutCirc',
}),
leave: (i) => ({
clipPath: [
'polygon(0 0, 100% 0, 100% 100%, 0% 100%)',
'polygon(100% 0, 100% 0, 100% 100%, 100% 100%)',
],
delay: i * 10,
easing: 'easeInOutCirc',
}),
},
}
建立多個展示方塊呈現每個轉場,且點擊方塊可以切換顯示狀態。
src\components\text-characters-transition\examples\transition-type.vue
<template>
<div class="flex flex-col gap-4 w-full">
<div class="flex flex-col items-center gap-2 text-3xl font-bold tracking-wider">
<div
v-for="(item, i) in list"
:key="i"
class="clickable-box relative border px-10 py-4"
:class="{ 'border-x-4': item.visible }"
@click="toggleVisible(item)"
>
<text-characters-transition
label="一段展示用的文字"
v-bind="item"
class=" pointer-events-none"
/>
<div class=" absolute left-0 bottom-0 p-2 px-3 text-sm font-normal tracking-normal opacity-20">
{{ item.name }}
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ExtractComponentProps } from '../../../types';
import TextCharactersTransition from '../text-characters-transition.vue';
type Param = ExtractComponentProps<typeof TextCharactersTransition>
type Item = Pick<Param, 'name' | 'visible'>;
const list = ref<Item[]>([
{
visible: false,
name: 'blur',
},
{
visible: false,
name: 'clip-right'
},
]);
function toggleVisible(item: Pick<Param, 'visible'>) {
item.visible = !item.visible;
}
</script>
<style scoped lang="sass">
.clickable-box
cursor: pointer
transition-duration: 0.4s
&:active
transition-duration: 0.1s
scale: 0.98
</style>
在文件中引入範例。
docs\components\text-characters-transition\index.md
...
<script setup>
...
import TransitionType from '../../../src/components/text-characters-transition/examples/transition-type.vue'
</script>
...
### 轉場類型
元件內建了一些簡單的效果,來試試吧。◝( •ω• )◟
(點擊以下任一方塊,開始切換)
<transition-type/>
::: details 查看範例原始碼
<<< ../../../src/components/text-characters-transition/examples/transition-type.vue
:::
...
看起來很讚讚。( •̀ ω •́ )✧
示範如何自定義過場,讓使用者發揮創意。
展示方塊沿用上一個範例。
src\components\text-characters-transition\examples\custom-transition.vue
<template>
<div class="flex flex-col gap-4 w-full">
<div class="flex-1 flex flex-col justify-around items-center gap-6 text-xl">
<div
v-for="(item, i) in list"
:key="i"
class=" clickable-box border px-9 py-6"
:class="{ 'border-x-4': item.visible }"
@click="toggleVisible(item)"
>
<text-characters-transition v-bind="item" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ExtractComponentProps } from '../../../types';
import anime from 'animejs';
import { sample } from 'remeda';
import TextCharactersTransition from '../text-characters-transition.vue';
type Param = ExtractComponentProps<typeof TextCharactersTransition>
type Item = Pick<Param, 'label' | 'enter' | 'leave' | 'visible'> & {
class?: string;
};
const negativeList = [1, -1] as const;
/** 隨機正負 */
const randomNegative = () => sample(negativeList, 1)[0];
const list = ref<Item[]>([
{
visible: false,
label: '程式如詩寫,美到無人解',
class: 'font-wenkai tracking-[0.2rem]',
enter: (i) => ({
opacity: [0, 1],
filter: ['blur(20px)', 'blur(0px)'],
translateX: () => [
anime.random(40, 60) * randomNegative(),
0,
],
translateY: () => [
anime.random(50, 60) * randomNegative(),
0
],
delay: i * 100,
duration: 1600,
easing: 'easeOutCirc',
}),
leave: (i) => ({
opacity: 0,
filter: 'blur(20px)',
delay: i * 50,
duration: 900,
easing: 'easeInCirc',
}),
},
{
visible: false,
class: 'tracking-[0.2rem] perspective',
label: ['人', '和', '程式', ',', '一個', '能跑', '就行'],
enter: (i) => ({
opacity: [0, 1],
rotateX: [anime.random(180, 90), 0],
rotateY: [270, 0],
rotateZ: [anime.random(-90, 90), 0],
scaleX: [0.5, 1],
easing: 'easeOutCirc',
duration: 1000,
delay: i * 300,
}),
leave: (i) => ({
opacity: 0,
rotateX: anime.random(-180, -90),
rotateY: anime.random(-90, 90),
rotateZ: anime.random(-90, 90),
scaleX: 0.5,
easing: 'easeInExpo',
duration: 1400,
delay: i * 100,
}),
},
])
function toggleVisible(item: Pick<Param, 'visible'>) {
item.visible = !item.visible;
}
</script>
<style scoped lang="sass">
@import url('https://fonts.googleapis.com/css2?family=LXGW+WenKai+Mono+TC&family=Noto+Sans:wght@100;200;300;400;500;600;700;800;900&display=swap')
.font-wenkai
font-family: "LXGW WenKai Mono TC", monospace
font-weight: 400
font-style: normal
text-shadow: 0 0 10px rgba(#111, 0.1)
.perspective
perspective: 100px
transform-style: preserve-3d
.clickable-box
cursor: pointer
transition-duration: 0.4s
&:active
transition-duration: 0.1s
scale: 0.98
</style>
在文件中引入範例。
docs\components\text-characters-transition\index.md
...
<script setup>
...
import CustomTransition from '../../../src/components/text-characters-transition/examples/custom-transition.vue'
</script>
...
### 自定義轉場
參數皆可自定義,寫法詳見 [anime.js 文件](https://animejs.com/documentation/#cssProperties)
來打造各種獨特的轉場效果!(≖‿ゝ≖)✧
(點擊以下任一方塊,開始切換)
<custom-transition />
::: details 查看範例原始碼
<<< ../../../src/components/text-characters-transition/examples/custom-transition.vue
:::
...
效果很讚!✧⁑。٩(ˊᗜˋ*)و✧⁕。
最後讓我們補充一下原理簡介。
docs\components\text-characters-transition\index.md
...
## 原理
切分文字後,將每個區塊建立唯一 id,利用 anime.js 實現動畫效果
## API
### Props
<<< ../../../src/components/text-characters-transition/text-characters-transition.vue/#Props
### Emits
<<< ../../../src/components/text-characters-transition/text-characters-transition.vue/#Emits
以上程式碼已同步至 GitLab,大家可以前往下載: