Vue动画事件详解及过渡动画实例


Posted in Javascript onFebruary 09, 2019

为了应用过渡效果,需要在目标元素上使用 transition 特性:

<div v-if="show" transition="my-transition"></div>

transition 特性可以与下面资源一起用:

v-if
v-show
v-for (只在插入和删除时触发,使用 vue-animated-list 插件)
动态组件
在组件的根节点上,并且被 Vue 实例 DOM 方法(如 vm.$appendTo(el))触发。

当插入或删除带有过渡的元素时,Vue 将:

尝试以 ID "my-transition" 查找 JavaScript 过渡钩子对象——通过 Vue.transition(id, hooks) 或 transitions 选项注册。如果找到了,将在过渡的不同阶段调用相应的钩子。
自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。
如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作(插入/删除)在下一帧中立即执行。

CSS 过渡

示例

典型的 CSS 过渡像这样:

<div v-if="show" transition="expand">hello</div>

然后为 .expand-transition, .expand-enter 和 .expand-leave 添加 CSS 规则:

/* 必需 */
.expand-transition {
 transition: all .3s ease;
 height: 30px;
 padding: 10px;
 background-color: #eee;
 overflow: hidden;
}

/* .expand-enter 定义进入的开始状态 */
/* .expand-leave 定义离开的结束状态 */
.expand-enter, .expand-leave {
 height: 0;
 padding: 0 10px;
 opacity: 0;
}

你可以在同一元素上通过动态绑定实现不同的过渡:

<div v-if="show" :transition="transitionName">hello</div>
new Vue({
 el: '...',
 data: {
 show: false,
 transitionName: 'fade'
 }
})

另外,可以提供 JavaScript 钩子:

Vue.transition('expand', {

 beforeEnter: function (el) {
 el.textContent = 'beforeEnter'
 },
 enter: function (el) {
 el.textContent = 'enter'
 },
 afterEnter: function (el) {
 el.textContent = 'afterEnter'
 },
 enterCancelled: function (el) {
 // handle cancellation
 },

 beforeLeave: function (el) {
 el.textContent = 'beforeLeave'
 },
 leave: function (el) {
 el.textContent = 'leave'
 },
 afterLeave: function (el) {
 el.textContent = 'afterLeave'
 },
 leaveCancelled: function (el) {
 // handle cancellation
 }
})

过渡的 CSS 类名

类名的添加和切换取决于 transition 特性的值。比如 transition="fade",会有三个 CSS 类名:

.fade-transition 始终保留在元素上。
.fade-enter 定义进入过渡的开始状态。只应用一帧然后立即删除。
.fade-leave 定义离开过渡的结束状态。在离开过渡开始时生效,在它结束后删除。
如果 transition 特性没有值,类名默认是 .v-transition, .v-enter 和 .v-leave。

自定义过渡类名

我们可以在过渡的 JavaScript 定义中声明自定义的 CSS 过渡类名。这些自定义类名会覆盖默认的类名。当需要和第三方的 CSS 动画库,比如 Animate.css 配合时会非常有用:

<div v-show="ok" class="animated" transition="bounce">Watch me bounce</div>
Vue.transition('bounce', {
 enterClass: 'bounceInLeft',
 leaveClass: 'bounceOutRight'
})

显式声明 CSS 过渡类型

Vue.js 需要给过渡元素添加事件侦听器来侦听过渡何时结束。基于所使用的 CSS,该事件要么是 transitionend,要么是 animationend。

如果你只使用了两者中的一种,那么 Vue.js 将能够根据生效的 CSS 规则自动推测出对应的事件类型。但是,有些情况下一个元素可能需要同时带有两种类型的动画。比如你可能希望让 Vue 来触发一个 CSS animation,同时该元素在鼠标悬浮时又有 CSS transition 效果。这样的情况下,你需要显式地声明你希望 Vue 处理的动画类型 (animation 或是 transition):

Vue.transition('bounce', {
 // 该过渡效果将只侦听 `animationend` 事件
 type: 'animation'
})

过渡流程详解

当 show 属性改变时,Vue.js 将相应地插入或删除 <div> 元素,按照如下规则改变过渡的 CSS 类名:

如果 show 变为 false,Vue.js 将:
调用 beforeLeave 钩子;
添加 v-leave 类名到元素上以触发过渡;
调用 leave 钩子;
等待过渡结束(监听 transitionend 事件);
从 DOM 中删除元素并删除 v-leave 类名;
调用 afterLeave 钩子。
如果 show 变为 true,Vue.js 将:
调用 beforeEnter 钩子;
添加 v-enter 类名到元素上;
把它插入 DOM;
调用 enter 钩子;
强制一次 CSS 布局,让 v-enter 确实生效。然后删除 v-enter 类名,以触发过渡,回到元素的原始状态;
等待过渡结束;
调用 afterEnter 钩子。
另外,如果在它的进入过渡还在进行中时删除元素,将调用 enterCancelled 钩子,以清理变动或 enter 创建的计时器。反过来对于离开过渡亦如是。

上面所有的钩子函数在调用时,它们的 this 均指向其所属的 Vue 实例。编译规则:过渡在哪个上下文中编译,它的 this 就指向哪个上下文。

最后,enter 和 leave 可以有第二个可选的回调参数,用于显式控制过渡如何结束。因此不必等待 CSS transitionend 事件, Vue.js 将等待你手工调用这个回调,以结束过渡。例如:

enter: function (el) {
 // 没有第二个参数
 // 由 CSS transitionend 事件决定过渡何时结束
}

vs.

enter: function (el, done) {
 // 有第二个参数
 // 过渡只有在调用 `done` 时结束
}

<p class="tip">当多个元素一起过渡时,Vue.js 会批量处理,只强制一次布局。

CSS 动画
CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。

示例: (省略了兼容性前缀)

<span v-show="show" transition="bounce">Look at me!</span>
.bounce-transition {
 display: inline-block; /* 否则 scale 动画不起作用 */
}
.bounce-enter {
 animation: bounce-in .5s;
}
.bounce-leave {
 animation: bounce-out .5s;
}
@keyframes bounce-in {
 0% {
 transform: scale(0);
 }
 50% {
 transform: scale(1.5);
 }
 100% {
 transform: scale(1);
 }
}
@keyframes bounce-out {
 0% {
 transform: scale(1);
 }
 50% {
 transform: scale(1.5);
 }
 100% {
 transform: scale(0);
 }
}

JavaScript 过渡

也可以只使用 JavaScript 钩子,不用定义任何 CSS 规则。当只使用 JavaScript 过渡时,enter 和 leave 钩子需要调用 done 回调,否则它们将被同步调用,过渡将立即结束。

为 JavaScript 过渡显式声明 css: false 是个好主意,Vue.js 将跳过 CSS 检测。这样也会阻止无意间让 CSS 规则干扰过渡。

在下例中我们使用 jQuery 注册一个自定义的 JavaScript 过渡:

Vue.transition('fade', {
 css: false,
 enter: function (el, done) {
 // 元素已被插入 DOM
 // 在动画结束后调用 done
 $(el)
 .css('opacity', 0)
 .animate({ opacity: 1 }, 1000, done)
 },
 enterCancelled: function (el) {
 $(el).stop()
 },
 leave: function (el, done) {
 // 与 enter 相同
 $(el).animate({ opacity: 0 }, 1000, done)
 },
 leaveCancelled: function (el) {
 $(el).stop()
 }
})

然后用 transition 特性中:

<p transition="fade"></p>

渐近过渡

transition 与 v-for 一起用时可以创建渐近过渡。给过渡元素添加一个特性 stagger, enter-stagger 或 leave-stagger:

<div v-for="item in list" transition="stagger" stagger="100"></div>

或者,提供一个钩子 stagger, enter-stagger 或 leave-stagger,以更好的控制:

Vue.transition('stagger', {
 stagger: function (index) {
 // 每个过渡项目增加 50ms 延时
 // 但是最大延时限制为 300ms
 return Math.min(300, index * 50)
 }
})
Javascript 相关文章推荐
JavaScript中的几个关键概念的理解-原型链的构建
May 12 Javascript
js时间日期和毫秒的相互转换
Feb 22 Javascript
解决Extjs4中form表单提交后无法进入success函数问题
Nov 26 Javascript
利用js(jquery)操作Cookie的方法说明
Dec 19 Javascript
一行命令搞定node.js 版本升级
Jul 20 Javascript
JavaScript保存并运算页面中数字类型变量的写法
Jul 06 Javascript
JS实现课堂随机点名和顺序点名
Mar 09 Javascript
vue中Npm run build 根据环境传递参数方法来打包不同域名
Mar 29 Javascript
详解微信小程序调用支付接口支付
Apr 28 Javascript
vue中改变滚动条样式的方法
Mar 03 Javascript
javascript canvas封装动态时钟
Sep 30 Javascript
基于element-ui封装表单金额输入框的方法示例
Jan 06 Javascript
JavaScript ES6常用基础知识总结
Feb 09 #Javascript
Vue组件的使用及个人理解与介绍
Feb 09 #Javascript
Vue自定义指令写法与个人理解
Feb 09 #Javascript
Vue指令指令大全
Feb 09 #Javascript
vue基于两个计算属性实现选中和全选功能示例
Feb 08 #Javascript
vue计算属性get和set用法示例
Feb 08 #Javascript
vue多次循环操作示例
Feb 08 #Javascript
You might like
php中设置index.php文件为只读的方法
2013/02/06 PHP
php去除换行(回车换行)的三种方法
2014/03/26 PHP
php判断访问IP的方法
2015/06/19 PHP
thinkPHP5实现的查询数据库并返回json数据实例
2017/10/23 PHP
PHP中关于php.ini参数优化详解
2020/02/28 PHP
可自己添加html的伪弹出框实现代码
2013/09/08 Javascript
我的Node.js学习之路(二)NPM模块管理
2014/07/06 Javascript
JavaScript中扩展Array contains方法实例
2020/08/23 Javascript
jQuery入门基础知识学习指南
2015/08/14 Javascript
实例讲解js验证表单项是否为空的方法
2016/01/09 Javascript
Angularjs中使用layDate日期控件示例
2017/01/11 Javascript
基于vue-cli配置lib-flexible + rem实现移动端自适应
2017/12/26 Javascript
layui从数据库中获取复选框的值并默认选中方法
2018/08/15 Javascript
node.js使用免费的阿里云ip查询获取ip所在地【推荐】
2018/09/03 Javascript
Vue 框架之动态绑定 css 样式实例分析
2018/11/14 Javascript
layui 实现二级弹窗弹出之后 关闭一级弹窗的方法
2019/09/18 Javascript
详解Angular Karma测试的持续集成实践
2019/11/15 Javascript
JavaScript实现字符串与HTML格式相互转换
2020/03/17 Javascript
解决在Vue中使用axios POST请求变成OPTIONS的问题
2020/08/14 Javascript
Vue自定义组件双向绑定实现原理及方法详解
2020/09/03 Javascript
Ant Design的Table组件去除
2020/10/24 Javascript
解决vue-cli输入命令vue ui没效果的问题
2020/11/17 Javascript
Vue组件简易模拟实现购物车
2020/12/21 Vue.js
[01:34]完美“圣”典宣传片震撼发布,12.17与你不见不散
2016/12/16 DOTA
[54:18]DOTA2-DPC中国联赛 正赛 PSG.LGD vs LBZS BO3 第一场 1月22日
2021/03/11 DOTA
Python中dictionary items()系列函数的用法实例
2014/08/21 Python
Django使用Celery异步任务队列的使用
2018/03/13 Python
将tensorflow的ckpt模型存储为npy的实例
2018/07/09 Python
领导的自我鉴定
2013/12/28 职场文书
优秀的自荐信要注意哪些
2014/01/03 职场文书
招股说明书范本
2014/05/06 职场文书
法学专业毕业实习自我鉴定2014
2014/09/27 职场文书
2014年化妆品销售工作总结
2014/12/01 职场文书
《只有一个地球》教学反思
2016/02/16 职场文书
React中的Context应用场景分析
2021/06/11 Javascript
Python访问Redis的详细操作
2021/06/26 Python