vue动画过渡js钩子函数详解

  • 前言
  • js钩子函数运行时间
  • js钩子函数的过渡或动画
  • 总结
  • 结语

前言

转载请注明出处并附上链接。

本文中,enter(leave)过程指的是beforeEnter、enter、afterEnter(beforeLeave、leave、afterLeave)三个阶段。

阅读过程请着重看js部分。

js钩子函数运行时间

js钩子函数的运行时机分三种情况:

  1. 不显示指定参数done:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动画和过渡</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>#show {text-align: center;overflow: hidden;position: relative;}p {display: block;width: 100px;margin: 100px auto;border: 1px solid black;}
    </style>
    </head>
    <body>
    <div id="app"><div id="show"><button @click="show=!show">点击</button><!-- 使用javascript钩子函数 --><transition@before-enter="beforeEnter"@enter="enter"@after-enter="afterEnter"@before-leave="beforeLeave"@leave="leave"@after-leave="afterLeave"><p v-if="show">测试钩子函数</p></transition></div>
    </div>
    <script>const app = new Vue({el: '#app',data: {show: true,},methods: {beforeEnter(el) {console.log(1);},enter(el) {console.log(2);},afterEnter(el) {console.log(3);},beforeLeave(el) {console.log(4)},leave(el) {console.log(5);},afterLeave(el) {console.log(6);}},})
    </script>
    

```

运行结果:


可以看出,第一次点击进入leave过程,输出4、5、6(6稍停顿一会),p节点消失。再点击按钮,输出1、2、3,p节点出现。

  1. 显示指定done参数,但不调用:
 <script>const app = new Vue({el: '#app',data: {show: true,},methods: {beforeEnter(el) {console.log(1);},enter(el, done) {console.log(2);// done() 不调用},afterEnter(el) {console.log(3);},beforeLeave(el) {console.log(4)},leave(el, done) {console.log(5);// done()不调用},afterLeave(el) {console.log(6);}},})</script>

运行结果:


第一次点击按钮输出4、5,再次点击按钮输出1、6、2。注意这时p节点始终不消失,并且没有输出3(即afterEnter函数没有运行)

  1. 显示指定done参数,并且调用:
<script>const app = new Vue({el: '#app',data: {show: true,},methods: {beforeEnter(el) {console.log(1);},enter(el, done) {console.log(2);done()},afterEnter(el) {console.log(3);},beforeLeave(el) {console.log(4)},leave(el, done) {console.log(5);done()},afterLeave(el) {console.log(6);}},})</script>

运行结果:

第一次点击输出4、5、6 (6没有任何停顿),p节点消失。再次点击按钮输出1、2、3,p节点出现。

出项以上情况是因为,vue在定义js钩子函数时,会判断enter和leave钩子函数的参数个数,如果没有显示指定done参数,vue会自动判断动画或过渡的结束时间,并且执行afterEnter函数或afterLeave函数,此时在enter(leave)过程,beforeEnter、enter和afterEnter(beforeLeave、leave和afterLeave)是顺序执行的,元素节点也会紧跟着出现(消失)。vue自动判断动画或过渡效果结束时间是有些许滞后的,会导致afterEnter钩子函数和afterLeave钩子函数调用时间有所延迟(这就是为什么‘6’输出稍有停顿)。

ps: enter钩子函数也没有调用done,但是‘3’似乎并没有滞后输出或者延迟的不明显。

如果显示指定done参数,则表示手动决定动画或过渡的结束时间,调用done就表示动画或过渡结束,然后执行afterEnter函数或afterLeave函数,在之后节点消失或出现。
如果不调用done,vue会认为动画或过渡一直未结束,就不会有afterEnter函数或afterLeave函数的运行,节点也一直处于enter或leave阶段,所以节点并不会消失。但是当节点一直处于leave阶段时,再次点击了按钮使节点位于enter过程,vue就会自动结束上一个leave过程,执行afterLeave钩子函数。这也就是为什么在上面第三种情况中,‘6’会出现在‘1’之后。

js钩子函数的过渡或动画

vue教程中的原话:

这些钩子函数可以结合 CSS transitions/animations 使用,也可以单独使用。

1.当你利用 CSS transitions/animation实现动画过渡效果时,需要注意:

  1. 未渲染的节点 或 display为none的节点 本身是没法触发动画和过渡效果的。
  2. 在leave过程,如果调用done(),节点会很快消失,过渡效果就看不到了。

我们看一段代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>动画和过渡</title><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><style>#show {text-align: center;}</style>
</head><body><div id="app"><div id="show"><button @click="show=!show">点击</button><!-- 使用javascript钩子函数 --><transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @before-leave="beforeLeave"@leave="leave" @after-leave="afterLeave"><p v-if="show">测试钩子函数</p></transition></div></div><script>const app = new Vue({el: '#app',data: {show: true,},methods: {beforeEnter(el) {el.style.opacity = '0';el.style.transition ='all 1s';},enter(el) {el.style.opacity = '1';},afterEnter(el) {},beforeLeave(el) {el.style.transition ='all 1s';el.style.opacity = '1';},leave(el,done) {el.style.opacity = '0';done()},afterLeave(el) {}},})</script>
</body>
</html>

运行上面的代码你会发现,没有任何的动画过渡效果。对于上面第一个问题,你需要了解浏览器的渲染机制。浏览器并不是实时渲染的。而是处理完所有代码或者遇到一些特定代码才会引起浏览器的重排或者重绘。对与enter过程,执行完beforeEnter函数后,在浏览器页面中并没有为p节点加上transition和opacity属性,因为还有代码未处理完,直到之后enter函数运行完才会进行重绘过程。为元素节点加上transition和opacity=1(opacity=0被覆盖)属性。所以,只需要在enter钩子函数的 el.style.opacity = ‘0’ 前加入特定代码引起浏览器重绘或重排即可.

关于重排和重回可以看看 https://segmentfault.com/a/1190000016990089

对于第二个问题,手动调用done()函数,会导致vue认为过渡效果结束,让p节点迅速消失。可以让vue自动判断动画过渡效果的结束时间。

以下是解决方案:

<script>const app = new Vue({el: '#app',data: {show: true,},methods: {beforeEnter(el) {el.style.opacity = '0';el.style.transition ='all 1s';},enter(el) {//el.offsetWidth引起浏览器的重回el.offsetWidthel.style.opacity = '1';},afterEnter(el) {},beforeLeave(el) {el.style.transition ='all 1s';el.style.opacity = '1';},leave(el) {//不显示定义done参数,让vue自动判断动画结束时机el.style.opacity = '0';},afterLeave(el) {}},})</script>

运行效果:

2.单独使用js钩子函数实现动画效果:

理解了上面js钩子函数的运行机制,单独使用就不难了。需要留意vue官方教程中的原提醒:

当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

下面是一个实例:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>动画和过渡</title><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><style>#show {text-align: center;overflow: hidden;position: relative;}p {display: block;width: 100px;margin: 100px auto;border: 1px solid black;}</style>
</head><body><div id="app"><div id="show"><button @click="show=!show">点击</button><!-- 使用javascript钩子函数 --><transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @before-leave="beforeLeave"@leave="leave" @after-leave="afterLeave"><p v-if="show">测试钩子函数</p></transition></div></div><script>const app = new Vue({el: '#app',data: {show: true,},methods: {beforeEnter(el) {console.log(1);el.style.position = 'relative';},enter(el, done) {console.log(2);clearInterval(this.leaveTimer);this.enterTimer = setInterval(() => {let style = document.defaultView.getComputedStyle(el, null);let x = parseInt(style.left);console.log('enter');el.style.left = (x + 10) + 'px';}, 1000);done();},afterEnter(el) {console.log(3);},beforeLeave(el) {el.style.position = 'relative';console.log(4)},leave(el, done) {console.log(5);clearInterval(this.enterTimer);let count = 1;this.leaveTimer = setInterval(() => {let style = document.defaultView.getComputedStyle(el, null);let x = parseInt(style.left);console.log('leave');el.style.left = (x - 10) + 'px';}, 1000);},afterLeave(el) {console.log(6);}},})</script>
</body>
</html>

运行效果:

如果,上面代码enter 和 leave函数中都不指定done参数,那么就看不到离开的动画效果了。因为过渡效果将会立即完成。

总结

  1. done参数用于指定动画或过渡的结束时机。如果不指定done参数,表示由vue自动判断动画或者过渡的结束时机。但是此时,会导致元素在enter过程,beforeEnter,enter,afterEnter顺序执行而且元素是瞬间渲染出来的。同样的在leave过程,beforeleave,leave,afterleave会顺序执行并且元素会快速消失,leave阶段的过渡动画效果不生效,因为此时元素已经移除了。

  2. 如果指定done参数,调用done()表示的是动画或过渡效果结束,之后会执行afterEnter或afterLeave。

  3. 如果指定done参数不调用done,元素将一直处于enter(leave)阶段。若v-if状态一直不变,el元素一直不会移除。如果调用done,元素会立即消失。

结语

第一次写博客,以上皆为个人理解,若有误,敬请谅解, 感谢!

vue动画过渡 javascript钩子函数详解相关推荐

  1. JavaScript的函数详解

    JavaScript的函数详解 一.什么是函数 二.函数的使用 1.函数的声明 2.函数的调用 3.函数的参数:参入运算的数据 (1)形参(形式参数) (2)实参(实在参数): (3)参数之间的数据传 ...

  2. vue生命周期钩子函数详解

    先放一张官网生命周期图: vue有8种生命周期函数: 钩子函数 触发的行为 在此阶段可以做的事情 beforeCreadted vue实例的挂载元素$el和数据对象data都为undefined,还未 ...

  3. C语言 - 钩子函数详解

    自学到线程池 被各种函数指针的套娃操作套蒙了, 所以写一篇来总结一下. 首先要搞清楚几个事情 函数指针和指针函数 函数指针是指针,可以指向任一"同类型"的函数 指针函数是函数,这个 ...

  4. JavaScript valueOf() 函数详解

    valueOf()函数用于返回指定对象的原始值. 该方法属于Object对象,由于所有的对象都"继承"了Object的对象实例,因此几乎所有的实例对象都可以使用该方法. 所有主流浏 ...

  5. JavaScript闭包函数详解

    目录 闭包函数 变量作用域 闭包的概念 闭包的用途 闭包的缺点 闭包函数 变量作用域 要理解JavaScript闭包,就要先理解JavaScript的变量作用域. 变量的作用域有两种:全局的和局部的( ...

  6. javascript console 函数详解 js开发调试的利器 浏览:3201|更新:2014-05-30 09:27

    引用地址: http://jingyan.baidu.com/article/e75aca855c6419142edac6c1.html 一键约师傅 百度师傅最快的到家服务,最优质的电脑清灰! Con ...

  7. 详解Vue八大生命周期钩子函数

    摘要:Vue为生命周期中的每个状态都设置了钩子函数(监听函数) .每当Vue实例处于不同的生命周期时,对应的函数就会被触发调用. 本文分享自华为云社区<一文带你弄懂Vue八大生命周期钩子函数&g ...

  8. Javascript 函数详解

    Javascript 函数详解 1)函数声明: 通过关键字function定义,把函数作为变量来声明 函数声明后不会立即执行,会在我们需要的时候调用到. <script>function ...

  9. [js]JavaScript Number.toPrecision() 函数详解

    [js]JavaScript Number.toPrecision() 函数详解 JavaScript: numberObject.toPrecision( [ precision ] ) 如果没有提 ...

最新文章

  1. c语言正数与负数相加_C语言数据基本类型(1)
  2. linux 内存被修改,linux 查询内存(linux 修改 openfiles)
  3. zcmu-1646 盒子游戏
  4. 零基础小白学习UI设计的4个步骤
  5. 139. 单词拆分(JavaScript)
  6. loadrunner提示:Cannot save the license information because acceses to the registry is denied
  7. HTML表格和列表笔记练习!DOCTYPE html html lang=en head meta charset=UTF-8 title关于表格的一些练...
  8. java的ssh获取id,使用SSH公钥(id_dsa.pub)实现免密码登录
  9. 深度学习在NLP领域的发展之Transformer
  10. MySQL 基础操作
  11. Photoshop钢笔工具使用方法
  12. Mysql中怎样创建和使用存储过程
  13. 花生壳:域名诊断—客户端离线
  14. linux安装文件的后缀,Linux下各种后缀名文件安装
  15. SpringBoot项目实现qq邮箱验证码登录
  16. pdf文件怎么合并在一起
  17. QQ聊天记录统计可视化分析
  18. 华为应用市场AGC研习社直播:App个人信息安全保护审核标准解读
  19. 由113号元素鉨114号元素夫115号元素镆元素汞银金等元素构成的超导体
  20. Typora收费了, 还有哪些好用的markdown工具

热门文章

  1. 3dunet训练数据集
  2. 垃圾收集器与内存分配策略
  3. JavaWeb 项目 --- 在线 OJ 平台 (一)
  4. 【算法专题】重建二叉树
  5. 如何关闭电脑开机自启
  6. oracle nls date language,一个参数 nls_date_language
  7. mysql如何高效批量插入数据
  8. Protobuf —— .proto文件详解
  9. 吃瓜教程task01 第1章 绪论
  10. 机器学习实战(二)使用LightGBM的回归问题模型搭建