3、CSS动画实战:使用@keyframes定义动画、v-enter-active/v-leave-active配合animation、动画持续时间与延迟控制、结合第三方动画库(Animate.css)

好,咱们直接进入正题。CSS动画这块,说实话是Vue动画系统里最灵活、也最容易被低估的部分。很多人一上来就想着用JS库,其实纯CSS能解决大部分场景。我这些年做过的项目里,大概有70%的过渡动画都是用CSS搞定的。

3.1 @keyframes:动画的灵魂

先说说@keyframes。这东西说白了就是定义动画的「关键帧」。你告诉浏览器:从哪开始、到哪结束、中间经过哪些状态。剩下的中间过程,浏览器帮你算。

@keyframes slideIn {
  0% {
    transform: translateX(-100%);
    opacity: 0;
  }
  60% {
    transform: translateX(10%);
    opacity: 0.8;
  }
  100% {
    transform: translateX(0);
    opacity: 1;
  }
}

我个人习惯用百分比来定义关键帧,而不是from/to。为什么?因为百分比更灵活,你可以在中间插入更多状态。比如上面这个例子,我加了个60%的中间态,让元素先弹出去一点再回来,看起来更自然。

小技巧:关键帧不要太多,3-5个就够了。太多反而会让动画显得「碎」。我在项目中见过有人写了10个关键帧,结果动画看起来像抽风一样。

3.2 把@keyframes挂到Vue的过渡钩子上

现在问题来了:怎么把@keyframes和Vue的v-enter-active/v-leave-active结合起来?

其实很简单。你想想看,v-enter-active就是元素「入场」期间要执行的样式,v-leave-active就是「离场」期间。我们直接把animation属性写进去就行。

.my-enter-active {
  animation: slideIn 0.6s ease-out;
}

.my-leave-active {
  animation: slideOut 0.4s ease-in;
}

@keyframes slideOut {
  0% {
    transform: translateX(0);
    opacity: 1;
  }
  100% {
    transform: translateX(100%);
    opacity: 0;
  }
}

然后在模板里这样用:

<transition name="my">
  <div v-if="show" class="box">我是动画元素</div>
</transition>

嗯,这里要注意:Vue会自动把name属性的值拼到类名上。比如name="my",那入场动画的类就是my-enter-active,离场就是my-leave-active

我曾经踩过的坑:有一次我把animation写到了v-enterv-leave上,结果动画根本不执行。后来才发现,v-enter只是定义初始状态,真正执行动画的是v-enter-active。别搞混了。

3.3 动画持续时间与延迟控制

控制动画时长和延迟,说白了就是调两个参数:animation-durationanimation-delay

但这里有个坑——入场和离场的时长往往不一样。我个人习惯入场慢一点(0.5s-0.8s),离场快一点(0.2s-0.4s)。为什么?因为用户需要看清新元素怎么进来的,但旧元素离开时越快越好,别让人等着。

.fade-enter-active {
  animation: fadeIn 0.6s ease-out;
}

.fade-leave-active {
  animation: fadeOut 0.3s ease-in;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes fadeOut {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(-20px); }
}

延迟控制呢?animation-delay可以让你等一会儿再开始动画。这个在列表动画里特别有用——每个元素依次延迟一点点,形成「波浪效果」。

实战经验:列表动画的延迟建议用等差数列。比如第一个延迟0ms,第二个100ms,第三个200ms...这样看起来像多米诺骨牌一样依次倒下,视觉效果很舒服。

3.4 结合第三方动画库:Animate.css

说实话,自己写@keyframes虽然灵活,但有时候太慢了。尤其是项目赶工期的时候,哪有时间调那些缓动曲线?这时候就该请出Animate.css了。

Animate.css是个啥?说白了就是一个现成的动画库,里面预置了上百种动画效果。淡入淡出、弹跳、翻转、旋转...应有尽有。你只需要加个类名就行。

安装方式很简单:

npm install animate.css

然后在main.js里引入:

import 'animate.css'

接下来怎么和Vue的transition结合?我直接给你看代码:

<transition
  enter-active-class="animate__animated animate__bounceIn"
  leave-active-class="animate__animated animate__bounceOut"
>
  <div v-if="show" class="box">看我弹进来弹出去</div>
</transition>

看到了吗?enter-active-classleave-active-class这两个属性,直接替换了原来的v-enter-active类名。你只需要把Animate.css的类名填进去就行。

注意:Animate.css的类名都要加animate__animated前缀,这是他们v4版本的规定。我刚开始用的时候忘了加,折腾了半天才发现。

如果你想自定义动画时长,可以这样:

<transition
  enter-active-class="animate__animated animate__bounceIn"
  leave-active-class="animate__animated animate__bounceOut"
  :duration="600"
>
  <div v-if="show" class="box">时长统一为600ms</div>
</transition>

或者入场和离场分别控制:

<transition
  enter-active-class="animate__animated animate__bounceIn"
  leave-active-class="animate__animated animate__bounceOut"
  :duration="{ enter: 800, leave: 400 }"
>
  <div v-if="show" class="box">入场800ms,离场400ms</div>
</transition>

3.5 实战中的选择建议

说了这么多,到底什么时候自己写@keyframes,什么时候用Animate.css?我个人的经验是这样的:

场景 推荐方案 原因
简单的淡入淡出、滑动 自己写@keyframes 代码量少,性能好,不需要额外依赖
复杂的弹跳、翻转、旋转 Animate.css 现成的效果,省时省力
需要精细控制每个关键帧 自己写@keyframes Animate.css无法满足定制需求
项目赶工期、原型验证 Animate.css 快速出效果,后面再优化

最后说一句:不管用哪种方式,动画的目的是提升用户体验,不是炫技。我见过有人把页面做成「动画大杂烩」,每个元素都在跳,结果用户根本找不到重点。记住,克制才是最高级的审美。