iT邦幫忙

2024 iThome 鐵人賽

DAY 11
1

現在讓我們用更多範例讓使用者更了解「逐字轉場」元件吧。ヽ(●`∀´●)ノ

切分文字

展示如何自定義切分文字。

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

...

新增切分文字範例。◝( •ω• )◟

動畫.gif

轉場類型

可以切換不同過場類型。

不過目前只有淡入淡出,讓我們再多新增幾個動畫吧。

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

...

看起來很讚讚。( •̀ ω •́ )✧

動畫.gif

自定義過場

示範如何自定義過場,讓使用者發揮創意。

展示方塊沿用上一個範例。

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

...

效果很讚!✧⁑。٩(ˊᗜˋ*)و✧⁕。

動畫.gif

最後讓我們補充一下原理簡介。

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,大家可以前往下載:

GitLab - D11


上一篇
D10 - 逐字轉場:單元測試
下一篇
D12 - 逐字轉場:e2e 測試
系列文
要不要 Vue 點酷酷的元件?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言