该系列用于记录一些使用方法、demo 以及原理分析。本文介绍 transition 组件,和创建简单 demo 的过程。
# 动画过渡
Vue 的动画过渡做得挺强大的,不过平时总是做的管理类项目,几乎不怎么用到动画。这次也是因为要弄个讲课 PPT 才来仔细研究这块,开始以为照着官网看看差不多就可以了,后来才发现这块的内容超出本骚年的想象。嘛,还挺有意思的。
# Vue 过渡常用方式
Vue 过渡主要分为两类:CSS 动画和Javascript 动画。
根据官网 (opens new window)的说法,Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果,举例如下:
- 在 CSS 过渡和动画中自动应用 class(CSS 动画)
- 可以配合使用第三方 CSS 动画库,如 Animate.css(CSS 动画)
- 在过渡钩子函数中使用 JavaScript 直接操作 DOM(Javascript 动画)
- 可以配合使用第三方 JavaScript 动画库,如 Velocity.js(Javascript 动画)
嗯,也就是上面所说的两类,主要区分是否手动实现还是借用工具实现而已。
# 动画过渡的方法和原理
# 强大的 requestAnimationFrame
关于 requestAnimationFrame ,如果说没怎么写过动画的,或许几乎没听过。一般来说,大家常用的方式主要是来解决传说中浏览器刷新频率的问题。
在本骚年以前也写动画的日子里,通常是使用 jQuery ,各种计算然后调用 animate()
等。后面也接触了 CSS3 , transform 到 animation , CSS 的动画能力简直要上天了。
我们来看看MDN (opens new window)上是怎么介绍的吧。
window.requestAnimationFrame()
方法告诉浏览器您希望执行动画,并请求浏览器在下一次重绘之前调用指定的函数来更新动画。该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。
window.requestAnimationFrame(callback);
callback 一个在每次需要重新绘制动画时调用的包含指定函数的参数。这个回调函数有一个传参,DOMHighResTimeStamp,指示从触发 requestAnimationFrame 回调到现在(重新渲染页面内容之前)的时间。
返回值
一个 long 整数,请求 ID ,也是回调列表中唯一的标识。
可以传此值到 window.cancelAnimationFrame()
以取消回调函数。
关于 requestAnimationFrame 能做到的一些 CSS 不能做的,可以参考《CSS3 动画那么强,requestAnimationFrame 还有毛线用?》 (opens new window)看看。
总之,我们来看看 Vue 里面的相关代码:
// binding to window is necessary to make hot reload work in IE in strict mode
// 此处在不兼容时使用setTimeout进行向下兼容
const raf =
inBrowser && window.requestAnimationFrame
? window.requestAnimationFrame.bind(window)
: setTimeout;
export function nextFrame(fn: Function) {
raf(() => {
raf(fn);
});
}
nextFrame 就是 Vue 中用来 CSS 动画过渡的方法,可以在下一次重绘之前进行一些处理。后面讲 CSS 动画过渡的时候我们会再详细点分析。
# 关键的 transitionend 和 animationend
这两个分别是 CSS 动画中的结束事件, transitionend 是 CSS transition(如 transform/scale 等)结束的触发事件,animationend 则是 CSS 动画(keyframe)结束的触发事件。
# transitionend
transitionend 事件会在 CSS transition 结束后触发。以下两种情况不会触发:
- 当 transition 完成前移除 transition 时,比如移除 css 的 transition-property 属性。
- 在 transition 完成前设置 display 为"none"。
// 在指定的元素上监听transitionend事件
element.addEventListener("transitionend", callback, false);
# animationend
animationend 事件会在一个 CSS 动画完成时触发。与 transitionend 相似,animationend 的触发不包括完成前就已终止的情况,例如元素变得不可见或者动画从元素中移除。
// 在指定的元素上监听animationend事件
element.addEventListener("animationend", callback, false);
相比 CSS transition,CSS 动画还有相关的事件,包括:
- animationstart: animationstart 事件会在 CSS 动画开始时触发。如果有 animation-delay 延时,事件会在延迟时效过后立即触发
- animationiteration: 循环动画中,在每次循环结束时触发
- animationcancel: animationcancel 事件会在 CSS 异常终止时触发(即在未触发 animationend 事件的情况下停止运行)
Vue 的 CSS 过渡中会使用到这两个事件,后续会讲到。
# transition 组件
Vue 提供了 transition 的封装组件,可以给元素和组件添加 entering/leaving 过渡。
# transition 的使用
我们看看有哪些情况下可以使用 transition:
- 条件渲染 (使用 v-if )
- 条件展示 (使用 v-show )
- 动态组件
- 组件根节点
transition 的封装组件,主要是结合组件生命周期,在一些特殊逻辑(如 v-if、v-show、v-for)里增加钩子,来触发动画的实现。
我们知道,Vue 里面实现动画过渡有 CSS 和 Javascript 两种,而两种又是可以结合的,当然这是通过预埋的钩子以及上面讲到的 CSS 事件的方式来实现的。
至于具体的实现,后面分篇来讲一下,这里就不过多讲述了。
# 来个 demo
废话少说,直接甩个官网的例子 (opens new window):
<!-- transition的使用 -->
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
/* 简单的css transition实现动画 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
这里是使用的 CSS transition 方式来实现动画过渡的,我们看看在切换 v-if 的时候都发生了什么。
- v-if 绑定值的变更,导致插入或删除包含在 transition 组件中的元素。
- 自动嗅探目标元素是否应用了 CSS 过渡或动画。这里的确使用 CSS 过渡,于是会在元素添加时添加 CSS 类名,并判断动画加载完之后删除 CSS 类名。
- 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。(这里由于没有使用到,故不会执行)
- 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除) 在下一帧中立即执行。(当然在我们的例子中,这一步也不会生效)
# 结束语
本节我们简单介绍了 Vue 中 transition 封装组件的使用和 demo ,以及一些实现原理相关的基础知识。由于直接举的官方例子,这里效果页面大家可以到官网上看看就好啦。