Skip to content
Welcome to vote for your favorite component! You can also tell me anything you want to say! (*´∀`)~♥

Special Effects Transition transition

Cool effects and bold style Transition component! ◝( •ω• )◟

Attention!

This component uses the style filter property. Make sure you are not already using filter, otherwise the original filter effects will be lost. ლ(╹◡╹ლ)

Usage Examples

Basic Usage

Usage is the same as Vue's built-in Transition component.

(Click to start the transition)

View example source code
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-200 rounded-xl p-6">
    <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 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 and Leave

You can specify different effects for enter and leave separately.

Enter Effect
Leave Effect
View example source code
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-200 rounded-xl p-6">
    <div class="flex flex-col gap-4 border rounded py-4">
      <div class="flex items-center gap-1 px-4">
        <div class="w-20">
          {{ t('進入特效') }}
        </div>

        <div class="flex-1 border rounded">
          <select
            v-model="enterName"
            class="w-full p-2"
          >
            <option
              v-for="option in options"
              :key="option"
              :value="option"
            >
              {{ option }}
            </option>
          </select>
        </div>
      </div>

      <div class="flex items-center gap-1 px-4">
        <div class="w-20">
          {{ t('離開特效') }}
        </div>

        <div class="flex-1 border rounded">
          <select
            v-model="leaveName"
            class="w-full p-2"
          >
            <option
              v-for="option in options"
              :key="option"
              :value="option"
            >
              {{ option }}
            </option>
          </select>
        </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"
            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 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>

How It Works

These special effects go completely beyond the scope of CSS.

At first, I explored the HTML to Canvas approach, but converting HTML to Canvas produced too many inaccuracies, and the results were unbearable to look at. (́⊙◞౪◟⊙‵)

In the end, I found SVG Filter to be the best fit, because SVG Filters can directly apply filter effects to HTML elements.

This was a great opportunity to dive deep into SVG Filters -- quite complex, but truly fascinating. (*´∀`)~♥

The implementation concept is:

  1. SVG Filter content is separated into Vue components, with v-bind for parameter binding and animejs for animation.
  2. A unique ID is generated and bound to the target element's style to produce filter effects.

Source Code

API

Props

interface Props {
  appear?: boolean;
  enter?: EnterParams;
  leave?: LeaveParams;
}

Emits

const emit = defineEmits<{
  (e: 'init'): void;
  (e: 'beforeEnter'): void;
  (e: 'afterEnter'): void;
  (e: 'beforeLeave'): void;
  (e: 'afterLeave'): void;
}>()

Slots

defineSlots<{
  default?: () => unknown;
}>()

v0.60.0