Skip to content

Transition ​

17:06

Description ​

An enter/leave transition wrapper driven by CSS transition plus class switching (uni-app x on App does not support @keyframes, so it avoids them). Seven presets are built in — fade / slide-* / zoom-* — tunable via duration / timing-function / delay. Completion is judged by a duration + delay timer (App may not fire transitionend), so after-enter / after-leave fire after the configured time.

Compatibility ​

PlatformSupport
App✅ Supported (animation runs on CSS transition + class switching, not @keyframes; completion is timed by a timer, not transitionend)
H5✅ Supported
WeChat Mini Program✅ Supported

Examples ​

Basic Usage ​

show controls visibility with a fade transition by default; the component only handles the transition while content sizing is up to you.

View source
vue
<template>
    <ux-transition :show="show" name="fade" :duration="300">
        <view class="card">
            <text>过渡内容</text>
        </view>
    </ux-transition>
    <ux-button text="切换显示" type="primary" shape="round" @click="show = !show" />
</template>

<script setup lang="uts">
const show = ref(true);
</script>

Presets (name) ​

Seven presets: fade / slide-up / slide-down / slide-left / slide-right / zoom-in / zoom-out. Tap to switch and replay instantly.

View source
vue
<template>
    <!-- name 可选 fade / slide-up / slide-down / slide-left / slide-right / zoom-in / zoom-out -->
    <ux-transition :show="show" :name="current" :duration="300">
        <view class="card">
            <text>过渡内容</text>
        </view>
    </ux-transition>
    <ux-button text="重播动画" type="primary" shape="round" @click="replay" />
</template>

<script setup lang="uts">
const show = ref(true);
const current = ref('slide-up');

// 离场过渡结束后再进场,完成一次重播
const replay = () => {
    show.value = false;
    setTimeout(() => {
        show.value = true;
    }, 450);
};
</script>

Duration ​

duration sets the enter/leave transition length in milliseconds.

View source
vue
<template>
    <ux-transition :show="show" name="slide-up" :duration="duration">
        <view class="card">
            <text>过渡内容</text>
        </view>
    </ux-transition>
    <ux-button text="重播动画" type="primary" shape="round" @click="replay" />
</template>

<script setup lang="uts">
const show = ref(true);
const duration = ref(300);

const replay = () => {
    show.value = false;
    setTimeout(() => {
        show.value = true;
    }, duration.value + 150);
};
</script>

Timing Function ​

timing-function customizes the easing curve; the bounce curve adds elasticity to the animation.

View source
vue
<template>
    <ux-transition :show="show" name="zoom-in" :duration="500" :timing-function="timingFunction">
        <view class="card">
            <text>过渡内容</text>
        </view>
    </ux-transition>
</template>

<script setup lang="uts">
const show = ref(true);
// 默认曲线(标准);回弹曲线可取 cubic-bezier(0.175, 0.885, 0.32, 1.275)
const timingFunction = ref('cubic-bezier(0.2, 0.8, 0.2, 1)');
</script>

Delay ​

delay adds waiting time before the transition starts, applied to both enter and leave; completion events fire after duration + delay.

View source
vue
<template>
    <view class="row">
        <text>延迟 (ms)</text>
        <ux-number-box v-model="delay" :step="100" :min="0" :max="600" />
    </view>
    <ux-transition :show="show" name="slide-left" :duration="300" :delay="delay">
        <view class="card">
            <text>过渡内容</text>
        </view>
    </ux-transition>
</template>

<script setup lang="uts">
const show = ref(true);
const delay = ref(0);
</script>

First Render (appear) ​

When appear=true the enter animation plays on first mount; remount is required to reproduce it (outer v-if rebuild).

View source
vue
<template>
    <view class="row">
        <text>首次渲染播放进场动画</text>
        <ux-switch v-model="appear" />
    </view>
    <!-- 外层 v-if 重挂:appear 只在组件首次挂载时生效,重新挂载才能复现 -->
    <view v-if="mounted">
        <ux-transition :show="true" name="zoom-out" :duration="500" :appear="appear">
            <view class="card">
                <text>过渡内容</text>
            </view>
        </ux-transition>
    </view>
    <ux-button text="重新挂载" type="primary" shape="round" @click="remount" />
</template>

<script setup lang="uts">
const appear = ref(true);
const mounted = ref(true);

const remount = () => {
    mounted.value = false;
    setTimeout(() => {
        mounted.value = true;
    }, 50);
};
</script>

Events ​

Full lifecycle hooks: before-enter / enter / after-enter / enter-cancelled / before-leave / leave / after-leave / leave-cancelled.

View source
vue
<template>
    <ux-transition
        :show="show"
        name="slide-up"
        :duration="400"
        @before-enter="logEvent('before-enter')"
        @enter="logEvent('enter')"
        @after-enter="logEvent('after-enter')"
        @enter-cancelled="logEvent('enter-cancelled')"
        @before-leave="logEvent('before-leave')"
        @leave="logEvent('leave')"
        @after-leave="logEvent('after-leave')"
        @leave-cancelled="logEvent('leave-cancelled')"
    >
        <view class="card">
            <text>过渡内容</text>
        </view>
    </ux-transition>
    <ux-button text="切换显示" type="primary" shape="round" @click="show = !show" />
    <view class="log">
        <text v-for="(item, index) in logs" :key="index">{{ item }}</text>
    </view>
</template>

<script setup lang="uts">
const show = ref(true);
const logs = ref<string[]>([]);

const logEvent = (name: string) => {
    logs.value = ([name] as string[]).concat(logs.value.slice(0, 7));
};
</script>

Custom Styles (custom-class / custom-style) ​

custom-class extends the root class; custom-style applies inline styles.

View source
vue
<template>
    <ux-transition
        custom-class="my-transition"
        :custom-style="customStyle"
        :show="show"
        name="fade"
        :duration="400"
    >
        <view class="card">
            <text>过渡内容</text>
        </view>
    </ux-transition>
</template>

<script setup lang="uts">
const show = ref(true);
const customStyle = ref<UTSJSONObject>({
    'background-color': '#edf4ff',
    'border-radius': '8px'
});
</script>

<style scoped>
/* custom-class 外部类:为过渡根节点补充内边距 */
.my-transition {
    padding: 12px;
}
</style>

API ​

Props ​

PropertyDescriptionTypeDefaultVersion
customStyleCustom root element styleUTSJSONObject--
customClassCustom root element style classstring''-
showWhether the content is shown (default true)Booleantrue-
namePreset animation: fade / slide-up / slide-down / slide-left / slide-right / zoom-in / zoom-out (default fade)String'fade'-
durationEnter/leave animation duration in ms (default 300)Number300-
timingFunctionEasing curve (default cubic-bezier(0.2, 0.8, 0.2, 1))String'cubic-bezier(0.2, 0.8, 0.2, 1)'-
delayAnimation delay in ms, applied to both enter and leave (default 0)Number0-
appearWhether to play the enter animation on first render (default false)Booleanfalse-

Events ​

EventDescriptionParamsVersion
before-enterEntering begins--
enterThe enter animation actually starts (after the one-beat terminal-class switch following mount; in the re-open case it fires on the same beat as before-enter)--
after-enterThe enter animation ends--
enter-cancelledThe enter animation is interrupted by a leave before completing--
before-leaveLeaving begins--
leaveThe leave animation starts (same beat as before-leave, reserved)--
after-leaveThe leave animation ends (the DOM has been unmounted)--
leave-cancelledThe leave animation is interrupted by a re-enter before completing--

Slots ​

SlotDescriptionVersion
defaultThe content to transition (animated as a whole on enter/leave)-

Notes ​

  • appear only takes effect on the component's first mount; toggling show afterwards does not replay the enter animation — remount the component (outer v-if) to reproduce it.
  • Completion events (after-enter / after-leave) are judged by a duration + delay timer, not transitionend (App may not fire it), so they may be one beat off the actual rendered frame.
  • DOM is unmounted only after leave finishes; interrupting an enter with a leave emits enter-cancelled, and re-opening during a leave emits leave-cancelled.
  • An unknown name falls back to fade.
  • On App, transition-duration / transition-delay do not support multi-value lists, so duration / delay / curve are emitted inline as single values and the start/end properties come from the preset classes.