CSS过渡类名详解:从v-enter到自定义过渡
说实话,刚接触Vue过渡的时候,我也被那一堆类名搞晕过。v-enter、v-enter-active、v-enter-to……这到底谁先谁后?什么时候触发?今天咱们就把这事彻底捋清楚。
v-enter/v-leave类名的生命周期
Vue的过渡系统,说白了就是一套CSS类名的自动切换机制。当元素插入或移除时,Vue会在合适的时机加上或去掉特定的类名。
来看一个典型的进入动画流程:
/* 进入前 - 元素还没出现 */
.v-enter {
opacity: 0;
transform: translateY(20px);
}
/* 进入过程中 - 整个动画期间都生效 */
.v-enter-active {
transition: all 0.3s ease;
}
/* 进入结束 - 元素完全显示后的状态 */
.v-enter-to {
opacity: 1;
transform: translateY(0);
}
这里有个关键点,我刚开始学的时候踩过坑:v-enter 和 v-enter-to 是互斥的。元素刚插入时,v-enter生效,下一帧v-enter被移除,v-enter-to被加上。如果你在v-enter里设置了opacity: 0,又在v-enter-to里设置了opacity: 1,那transition就会从0过渡到1。
生命周期时间线(进入动画):
- 第0帧:元素插入DOM,v-enter和v-enter-active同时被添加
- 第1帧:v-enter被移除,v-enter-to被添加
- 过渡结束后:v-enter-active和v-enter-to被移除
离开动画正好反过来:
/* 离开前 - 元素还在 */
.v-leave {
opacity: 1;
}
/* 离开过程中 */
.v-leave-active {
transition: all 0.3s ease;
}
/* 离开结束 - 元素消失 */
.v-leave-to {
opacity: 0;
}
嗯,这里要注意:v-leave 其实很少用到。因为元素离开前就是它原本的样子,你通常不需要再声明一遍。我个人的习惯是,离开动画只写 v-leave-active 和 v-leave-to。
自定义过渡类名
默认的 v- 前缀虽然方便,但遇到多个不同动画时就尴尬了。总不能所有过渡都用同一套样式吧?
Vue提供了自定义类名的方案,通过 transition 组件的 props 传入:
<transition
enter-class="fade-enter"
enter-active-class="fade-enter-active"
enter-to-class="fade-enter-to"
leave-class="fade-leave"
leave-active-class="fade-leave-active"
leave-to-class="fade-leave-to"
>
<div v-if="show">自定义过渡</div>
</transition>
这样你就可以写自己的类名了:
.fade-enter {
opacity: 0;
}
.fade-enter-active {
transition: opacity 0.5s;
}
.fade-enter-to {
opacity: 1;
}
我在项目中经常用这个特性来区分不同组件的动画。比如弹窗用 slide-fade,列表用 list-enter,互不干扰。
小技巧:如果你用CSS预处理器(SCSS/LESS),可以把过渡类名定义成mixin,复用起来特别爽。
过渡模式:in-out 和 out-in
默认情况下,Vue的进入和离开动画是同时进行的。这会导致一个问题——两个元素同时存在,视觉上很乱。
举个例子,一个切换按钮:
<transition mode="out-in">
<button :key="currentTab">
{{ currentTab }}
</button>
</transition>
这里我用了 mode="out-in",意思是:先让旧元素离开,再让新元素进入。这样就不会出现两个按钮重叠的尴尬情况。
Vue提供了三种模式:
| 模式 | 行为 | 适用场景 |
|---|---|---|
| 默认(同时) | 进入和离开同时进行 | 简单的淡入淡出 |
| in-out | 新元素先进入,旧元素再离开 | 很少用,容易造成布局抖动 |
| out-in | 旧元素先离开,新元素再进入 | 最常用,切换体验流畅 |
说实话,in-out 模式我几乎没用过。你想啊,新元素先进来,旧元素还在,两个同时存在,除非你设计的就是叠加效果,否则看起来会很奇怪。
避坑指南:我曾经在列表切换时忘了加 mode,结果两个列表同时渲染,DOM结构都乱了。后来养成了习惯——只要涉及元素替换,必加 mode="out-in"。
实际项目中的组合用法
把上面这些知识点串起来,看看一个完整的例子:
<template>
<transition
name="custom"
mode="out-in"
enter-active-class="animate__animated animate__fadeIn"
leave-active-class="animate__animated animate__fadeOut"
>
<div :key="page" class="page-content">
{{ page }}
</div>
</transition>
</template>
这里我用了 Animate.css 的类名作为自定义过渡类名,配合 out-in 模式,页面切换效果非常丝滑。你想想看,如果不用自定义类名,每个动画都得手写,多累啊。
最后总结一下我的经验:
- v-enter/v-leave:记住它们的生命周期,尤其是第0帧和第1帧的区别
- 自定义类名:多组件项目必备,避免样式冲突
- 过渡模式:out-in 是首选,in-out 慎用
掌握了这些,Vue过渡的基础你就拿下了。下一章咱们聊聊 JavaScript 钩子,那才是真正玩出花的地方。