Vue过渡动画从入门到装X:淡入淡出、滑动、列表动画、第三方库全搞定

发布时间:2026/6/11 1:24:36
Vue过渡动画从入门到装X:淡入淡出、滑动、列表动画、第三方库全搞定 一、Vue动画靠什么两个组件打天下Vue 帮你封装好了两个组件Transition给单个元素或组件添加进入/离开动画。TransitionGroup给列表里的多个元素添加进入/离开动画还能加移动动画。你只需要把要做动画的元素包在里面然后给几个特定名字的 CSS 类写好样式Vue 就会在合适的时机自动添加/移除这些类动画就出来了。用人话讲你告诉 Vue “这个元素出来时要淡入走时要淡出”Vue 就帮你管什么时候加什么类你只负责写好类里面的 CSS 动画。二、最简单的淡入淡出先看一个最基础的例子点击按钮一段文字淡入淡出。vuetemplate div button clickshow !show切换显示/button !-- Transition 组件namefade 就是给动画起个名字 Vue 会根据这个名字去匹配 CSS 类 -- Transition namefade !-- 只有这一个元素会被加上动画类 -- p v-ifshow我会淡入淡出/p /Transition /div /template script setup import { ref } from vue // 控制元素显示隐藏 const show ref(false) /script style scoped /* 下面这几个类名是固定格式name-enter-from、name-enter-active 等等 因为 Transition 上的 name 是 fade所以类名都以 fade 开头 */ /* 进入的初始状态完全透明 */ .fade-enter-from { opacity: 0; } /* 进入的过程过渡 0.5 秒对 opacity 属性做动画 */ .fade-enter-active { transition: opacity 0.5s ease; } /* 进入的结束状态完全不透明其实这个是默认值可以不写 */ .fade-enter-to { opacity: 1; } /* 离开的初始状态完全不透明 */ .fade-leave-from { opacity: 1; } /* 离开的过程过渡 0.5 秒 */ .fade-leave-active { transition: opacity 0.5s ease; } /* 离开的结束状态完全透明 */ .fade-leave-to { opacity: 0; } /style代码拆解Transition namefade里的name是这个动画的名字随便起但别和别的冲突。CSS 类名格式name-进入/离开的阶段。-enter-from进入开始时的状态。-enter-active进入过程中的过渡效果这里写transition。-enter-to进入结束时的状态。-leave-from离开开始时的状态。-leave-active离开过程中的过渡效果。-leave-to离开结束时的状态。我们只在-enter-active和-leave-active里写了transition告诉 Vue “当状态变化时用 0.5 秒平滑过渡”。v-ifshow切换时Vue 会自动给这个p元素依次加上fade-enter-from、fade-enter-active、fade-enter-to这几个类。三、其实可以更简洁利用默认状态省略一些类很多时候-enter-to和-leave-from就是元素本来的样子不用专门写。上面的 CSS 可以精简为css.fade-enter-from, .fade-leave-to { opacity: 0; } .fade-enter-active, .fade-leave-active { transition: opacity 0.5s ease; }解释进入开始和离开结束都是透明opacity: 0。进入结束和离开开始都是不透明默认所以不用写。只要在-active里写好transitionVue 就会自动补齐中间状态。这样以后你写动画基本就记住这两个类就行。四、给弹窗加个滑入滑出效果淡入淡出太普通咱们试试从上面滑下来消失时滑上去。vuetemplate div button clickshowModal !showModal切换弹窗/button !-- 这次 name 叫 slide -- Transition nameslide div v-ifshowModal classmodal p我是一个弹窗/p button clickshowModal false关闭/button /div /Transition /div /template script setup import { ref } from vue const showModal ref(false) /script style scoped .modal { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: white; padding: 20px; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); } /* 进入的初始状态向上偏移 30px且透明 */ .slide-enter-from { opacity: 0; transform: translateY(-30px); } /* 离开的结束状态同样向上偏移并透明 */ .slide-leave-to { opacity: 0; transform: translateY(-30px); } /* 进入和离开的过程过渡 0.3 秒 */ .slide-enter-active, .slide-leave-active { transition: all 0.3s ease; } /style关键点transform: translateY(-30px)让元素在 Y 轴上移 30px。配合opacity就形成了“从上方滑入并淡入”的效果。离开时反过来滑上去并淡出。五、自定义过渡类名用第三方动画库 Animate.css自己写 CSS 动画有时候挺麻烦社区有很多现成的动画库比如Animate.css里面有几十种预设动画弹入、翻转、抖动等。Vue 的Transition允许你自定义过渡的类名直接用 Animate.css 的类名。第一步在index.html里引入 Animate.css或者 npm 安装导入htmllink relstylesheet hrefhttps://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css /第二步在组件里用vuetemplate div button clickshow !show切换动画/button !-- 关键属性 enter-active-class 指定进入过程使用的类 leave-active-class 指定离开过程使用的类 这里直接写 Animate.css 的类名 -- Transition enter-active-classanimate__animated animate__bounceIn leave-active-classanimate__animated animate__bounceOut div v-ifshow classbox 我会弹入弹出 /div /Transition /div /template script setup import { ref } from vue const show ref(false) /script style scoped .box { width: 200px; height: 100px; background: #42b983; color: white; display: flex; align-items: center; justify-content: center; border-radius: 8px; } /style解释enter-active-class替代了之前的name-enter-active直接指定进入时用的 CSS 类。Animate.css 的类名格式是animate__animated 具体动画名如animate__bounceIn。这样你就能瞬间用上几十种预设动画完全不用自己写关键帧。六、给组件切换加过渡mode 属性有时候我们要在两个组件之间切换比如登录页和注册页。默认情况下一个组件离开和另一个组件进入是同时进行的可能会有点视觉上的重叠。Transition有个mode属性可以设置成out-in当前元素先离开完成后新元素再进入推荐。in-out新元素先进入完成后旧元素再离开。vuetemplate div button clickisLogin !isLogin 切换到 {{ isLogin ? 注册 : 登录 }} /button !-- modeout-in 保证旧组件完全离开后新组件才进入 -- Transition nameswitch modeout-in LoginForm v-ifisLogin keylogin / RegisterForm v-else keyregister / /Transition /div /template script setup import { ref } from vue import LoginForm from ./LoginForm.vue import RegisterForm from ./RegisterForm.vue const isLogin ref(true) /script style scoped .switch-enter-from, .switch-leave-to { opacity: 0; transform: translateX(20px); } .switch-enter-active, .switch-leave-active { transition: all 0.3s ease; } /style重点两个组件用v-if/v-else切换。别忘了加key不然 Vue 会复用组件动画可能失效。modeout-in让切换更流畅。七、列表动画TransitionGroup前面都是单个元素的进入/离开。列表呢比如购物车删除一项其他项往上移动时能不能也加个动画用TransitionGroup。vuetemplate div button clickaddItem添加一项/button button clickremoveItem删除最后一项/button !-- TransitionGroup 组件tagul 表示渲染成 ul 标签 namelist 给动画起名 -- TransitionGroup namelist tagul li v-foritem in items :keyitem.id classlist-item {{ item.text }} button clickremoveSpecific(item.id)删除/button /li /TransitionGroup /div /template script setup import { ref } from vue // 初始数据 const items ref([ { id: 1, text: 第一项 }, { id: 2, text: 第二项 }, { id: 3, text: 第三项 } ]) let nextId 4 function addItem() { items.value.push({ id: nextId, text: 第${nextId - 1}项 }) } function removeItem() { items.value.pop() } function removeSpecific(id) { items.value items.value.filter(item item.id ! id) } /script style scoped .list-item { padding: 10px; margin: 5px; background: #f9f9f9; border: 1px solid #ddd; border-radius: 4px; list-style: none; } /* 进入和离开的动画 */ .list-enter-from, .list-leave-to { opacity: 0; transform: translateX(30px); } .list-enter-active, .list-leave-active { transition: all 0.5s ease; } /* 这个类很特殊list-move 当列表里的元素因为其他元素的位置变化而移动时 Vue 会给它加上这个类让你能添加平滑移动动画 */ .list-move { transition: transform 0.5s ease; } /style解释TransitionGroup会渲染成真实的标签这里tagul。每个v-for出来的元素必须有唯一的key。.list-move这个类用来处理其他元素移动时的过渡让列表变化更平滑。比如删除一项下面所有项会往上移这个过程会加上list-move的过渡。八、实战带过渡动画的待办事项列表我们综合一下做一个完整的待办事项包含添加、完成删除、全部清空并且有滑动淡入淡出效果。vuetemplate div classtodo-app h2待办事项/h2 !-- 输入框和添加按钮 -- div classinput-group input v-modelnewTodoText keyup.enteraddTodo placeholder输入待办内容回车添加 / button clickaddTodo添加/button /div !-- 待办列表使用 TransitionGroup -- TransitionGroup nametodo tagul classtodo-list li v-fortodo in todos :keytodo.id classtodo-item span :class{ done: todo.completed }{{ todo.text }}/span div button clicktoggleComplete(todo.id) {{ todo.completed ? 撤销 : 完成 }} /button button clickremoveTodo(todo.id)删除/button /div /li /TransitionGroup !-- 空状态提示 -- p v-iftodos.length 0 classempty暂无待办添加一条吧/p !-- 底部操作 -- div v-iftodos.length 0 classfooter span共 {{ todos.length }} 项/span button clickclearCompleted清除已完成/button /div /div /template script setup import { ref } from vue const newTodoText ref() const todos ref([]) let nextId 1 function addTodo() { const text newTodoText.value.trim() if (!text) return // 空内容不添加 todos.value.push({ id: nextId, text, completed: false }) newTodoText.value // 清空输入框 } function removeTodo(id) { todos.value todos.value.filter(todo todo.id ! id) } function toggleComplete(id) { const todo todos.value.find(todo todo.id id) if (todo) { todo.completed !todo.completed } } function clearCompleted() { todos.value todos.value.filter(todo !todo.completed) } /script style scoped .todo-app { max-width: 500px; margin: 0 auto; } .input-group { display: flex; gap: 10px; margin-bottom: 20px; } .input-group input { flex: 1; padding: 6px 12px; border: 1px solid #ccc; border-radius: 4px; } .todo-list { list-style: none; padding: 0; } .todo-item { display: flex; justify-content: space-between; align-items: center; padding: 10px; margin-bottom: 8px; background: #f5f5f5; border-radius: 4px; } .todo-item .done { text-decoration: line-through; color: #999; } .empty { text-align: center; color: #999; } .footer { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; padding-top: 10px; border-top: 1px solid #eee; } /* 待办项的进入/离开动画 */ .todo-enter-from { opacity: 0; transform: translateX(-20px); } .todo-leave-to { opacity: 0; transform: translateX(20px); } .todo-enter-active, .todo-leave-active { transition: all 0.4s ease; } /* 其他元素移动时的平滑过渡 */ .todo-move { transition: transform 0.4s ease; } /style效果添加事项时新项从左侧滑入并淡入。删除时项向右侧滑出并淡出。完成的事项会加删除线但不影响动画。下方元素上移时平滑过渡。九、几个常见坑和技巧1. 必须有 key在Transition里用v-if/v-else切换多个元素时每个元素要加key不然 Vue 会复用 DOM动画可能不生效。在TransitionGroup里v-for的每个项必须有唯一key。2. 元素不要设置display: none动画依赖元素的尺寸和位置如果加了display: noneVue 可能获取不到初始状态动画会失效。3. 过渡模式用out-in更流畅组件切换时modeout-in能让上一个完全出去后下一个再进来避免重叠感。4. 结合 JavaScript 钩子做复杂动画除了 CSSTransition还支持before-enter、enter、leave等 JavaScript 钩子你可以用 GSAP 等库做更复杂的动画。这里先不展开知道有这个能力就行。十、总结今天我们学会了Transition给单个元素/组件加进入离开动画。TransitionGroup给列表元素加动画还能处理元素移动。CSS 类命名规则name-enter-from、name-enter-active、name-leave-to等。自定义类名配合 Animate.css 等库直接用现成动画。mode属性控制多个元素切换时的顺序。动画是用户体验的润滑剂不用写太多关键的地方加一点点页面档次立马不一样。建议你把这些案例都敲一遍尤其是待办事项那个包含了大部分常用技巧改成你自己的项目就能用。有问题评论区说我挨个回。下篇咱们聊Vue 的组合式函数Composables把逻辑抽取得更优雅