Code前端首页关于Code前端联系我们

一、Vue2 里的动画基础逻辑是啥?

terry 12小时前 阅读数 11 #Vue
文章标签 Vue2;动画逻辑

p>咱做前端项目时,页面动效好不好看、流不流畅,直接影响用户体验,Vue2 作为曾经的前端框架顶流,内置的动画机制能让页面元素的「出场」「退场」更丝滑,但不少同学刚接触时,总搞不清咋把静态元素变「活」,比如过渡类名咋用、列表动画咋搞、和第三方库咋配合…今天就用问答形式,把 Vue2 动画从基础到实战的门道唠明白~


要理解 Vue2 动画,得先抓住「进入」和「离开」这两个核心阶段——元素插入 DOM(进入)、元素从 DOM 移除(离开)时,Vue 会通过内置组件帮我们控制过渡效果。

Vue 提供了 <transition><transition-group> 两个组件:

  • <transition> 负责单元素/单组件的进入、离开动画(比如弹窗显示/隐藏);
  • <transition-group> 负责列表类多元素的动画(todo 列表添加/删除项),因为列表有多个元素,还需要给每个元素加唯一 key 让 Vue 跟踪变化。

在动画执行过程中,Vue 会自动给元素添加/删除过渡类名,以进入过程为例,类名变化是:v-enter(初始状态)→ v-enter-active(激活状态,定义过渡/动画的时长、曲线等)→ v-enter-to(结束状态);离开过程则是 v-leavev-leave-activev-leave-to

这些类名里的 v- 是默认前缀,要是给 <transition name="my-anime">,类名就会变成 my-anime-enter 这种形式,简单说,Vue 是通过控制类名的增减,让 CSS 动画/过渡能按「阶段」执行~

只用 Vue 自身特性,咋给元素加过渡动画?

<transition> 配合 CSS 就能实现基础过渡!举个「淡入淡出弹窗」的例子,代码结构和思路如下:

<template>
  <div>
    <button @click="show = !show">切换弹窗</button>
    <!-- 用 transition 包裹需要动画的元素,name 指定类名前缀 -->
    <transition name="fade">
      <div class="box" v-show="show">我是带淡入淡出的弹窗</div>
    </transition>
  </div>
</template>
<style>
/* 进入和离开的「激活阶段」:定义过渡的属性、时长、曲线 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease; 
}
/* 进入前的初始状态、离开后的结束状态:透明度为 0 */
.fade-enter,
.fade-leave-to {
  opacity: 0; 
}
.box {
  width: 200px;
  height: 100px;
  background: #f4f4f4;
  text-align: center;
  line-height: 100px;
}
</style>
<script>
export default {
  data() {
    return { show: false };
  }
};
</script>

关键点拆解:

  1. 组件包裹<transition> 必须包裹需要动画的元素,且元素要用 v-ifv-show 控制显示/隐藏;
  2. 类名规则:通过 name 指定类名前缀(如 fade),CSS 里对应写 fade-enter-active 这类类名;
  3. CSS 过渡逻辑enter-activeleave-active 里写 transition(或 animation),控制「过渡时长、属性、曲线」;enterleave-to 控制「起始/结束样式」(比如透明度、位移、缩放)。

哪怕不用第三方库,靠这套逻辑也能实现「滑入滑出」「缩放」「旋转」等基础动效~

列表动画在 Vue2 里咋实现?

列表和单元素动画的核心区别是「多元素 + 位置变化」,这时候得用 <transition-group>,还要注意 key 的使用!

举个「todo 列表添加/删除动画」的例子:

<template>
  <div>
    <input v-model="newTodo" placeholder="输入任务" />
    <button @click="addTodo">添加任务</button>
    <!-- transition-group 包裹列表,tag 指定渲染成 ul(默认是 span) -->
    <transition-group name="list" tag="ul">
      <li 
        v-for="(todo, index) in todos" 
        :key="todo.id"  <!-- 必须用唯一 id,别用 index! -->
        @click="removeTodo(index)"
      >
        {{ todo.text }}
      </li>
    </transition-group>
  </div>
</template>
<style>
/* 进入、离开、移动的激活阶段:统一过渡规则 */
.list-enter-active,
.list-leave-active,
.list-move {
  transition: all 0.5s ease;
}
/* 进入前、离开后的样式:透明 + 向下位移 */
.list-enter,
.list-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
/* 离开过程的中间状态:让删除动画更自然(可选) */
.list-leave-active {
  position: absolute; 
}
ul {
  list-style: none;
  padding: 0;
}
li {
  background: #f9f9f9;
  margin: 5px 0;
  padding: 10px;
  cursor: pointer;
}
</style>
<script>
export default {
  data() {
    return {
      newTodo: "",
      todos: [],
      id: 1,
    };
  },
  methods: {
    addTodo() {
      if (this.newTodo.trim()) {
        this.todos.push({ id: this.id++, text: this.newTodo });
        this.newTodo = "";
      }
    },
    removeTodo(index) {
      this.todos.splice(index, 1);
    },
  },
};
</script>

核心要点:

  • 组件选择:列表必须用 <transition-group>,它会把多个元素当作「一组」处理;
  • 唯一 keyv-forkey 必须绑定唯一标识(比如后端返回的 id),千万别用索引!否则删除时 Vue 无法识别元素,动画会乱套;
  • 移动过渡:新增 .list-move 类,专门处理「列表项位置变化」的过渡(比如删除中间一项,其他项移动的动画);
  • 离开定位:给 .list-leave-activeposition: absolute,避免删除时元素占位影响其他项的布局动画。

Vue2 动画能和第三方动画库结合吗?咋操作?

必须能!不管是 CSS 动画库(如 Animate.css)还是 JS 动画库(如 Velocity.js),都能和 Vue2 动画机制无缝配合~

和 Animate.css(CSS 动画库)结合

Animate.css 提供了上百种现成的动画类(bounce「弹跳」、fadeIn「淡入」),直接拿过来用能省大量 CSS 代码,步骤如下:

  • 安装引入:通过 npm i animate.css 安装,然后在 main.js 里引入:

    import "animate.css"; 
  • <transition> 里指定类名:利用 enter-active-class「进入时的激活类」、leave-active-class「离开时的激活类」,绑定 Animate.css 的类名:

    <transition
      name="custom"
      enter-active-class="animate__animated animate__bounceIn"
      leave-active-class="animate__animated animate__bounceOut"
    >
      <div v-show="show">带弹跳效果的弹窗</div>
    </transition>

    注意:Animate.css 新版(4.x+)类名带 animate__ 前缀,必须和类名对应上~

和 Velocity.js(JS 动画库)结合

如果需要更复杂的「JS 控制动画」(比如根据用户行为动态改动画参数),可以用 <transition>钩子函数@enter「进入钩子」、@leave「离开钩子」):

<transition
  @enter="handleEnter"
  @leave="handleLeave"
>
  <div v-show="show">JS 控制动画的元素</div>
</transition>
<script>
import Velocity from "velocity-animate"; // 引入 Velocity.js
export default {
  methods: {
    handleEnter(el, done) {
      // el 是当前元素,done 是动画结束的回调(必须调用!)
      Velocity(el, { opacity: 1, translateY: 0 }, { duration: 500, complete: done });
    },
    handleLeave(el, done) {
      Velocity(el, { opacity: 0, translateY: "30px" }, { duration: 500, complete: done });
    },
  },
};
</script>

原理:Vue 在「进入阶段」会触发 @enter 钩子,执行 JS 动画逻辑;动画结束后必须调用 done() 告诉 Vue 进入阶段结束,否则后续流程会卡住,离开阶段同理~

做 Vue2 动画时,性能优化要注意啥?

动画多了容易卡,特别是列表动画或频繁切换的场景,这几个优化点得记牢:

优先用「性能友好」的 CSS 属性

动画尽量用 transformopacity,这俩属性触发的是「合成层渲染」,性能比 widthheightlefttop 这些「触发重排/重绘」的属性好得多,比如实现「滑动效果」,用 transform: translateX() 代替 left 值变化。

合理选择 v-showv-if

  • 如果元素是频繁切换显示(比如弹窗每秒切换一次),用 v-show(只切换样式,不销毁 DOM);
  • 如果元素切换后长时间不显示(比如用户点击后只弹一次的提示框),用 v-if(销毁 DOM 节省资源)。

列表动画里 key 要「稳」

千万别用索引(index)当 key!todo 列表用 indexkey,删除一项后,后面所有项的 key 都会变化,Vue 会把 DOM 全删了重建,动画直接炸锅还巨卡。必须用后端返回的唯一 idkey

大列表分批渲染

如果列表有几百条数据,一次性渲染动画会卡死,可以用 vue-virtual-scroller 这类「虚拟滚动库」,只渲染「可视区域」的元素,减少动画压力。

will-change 提前声明

如果动画元素的 transformopacity 会变化,可以在样式里加 will-change: transform;,让浏览器提前准备渲染资源,减少卡顿(但别滥用,会占内存)。

<keep-alive> 缓存组件状态

如果组件切换时(比如路由切换)要保留动画状态,用 <keep-alive> 缓存组件,避免组件销毁重建时重复执行动画,也能减少性能消耗~

Vue2 动画的核心逻辑与实践

Vue2 的动画机制把复杂的 DOM 操作和状态管理「封装」了,不管是基础过渡、列表动效,还是结合第三方库,核心都是利用 <transition>/<transition-group> 的「阶段控制」+「类名/钩子函数」,把 CSS/JS 动画串起来

实操时别光看理论,多练例子更有效:比如做个「带入场动画的导航菜单」「带删除动画的表格」「和 Animate.css 结合的加载动效」… 练着练着就摸透规律啦~

要是你在实操中碰到「动画不触发」「列表动画乱跳」这类问题,先检查这几点:<transition> 有没有正确包裹元素?key 是不是唯一?类名前缀和 CSS 有没有对应?钩子函数里的 done() 有没有调用?把这些细节吃透,Vue2 动画就能玩得很溜~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门