场景描述

在使用JS控制动画时一般需要在动画结束后执行回调去进行DOM的相关操作,所以需要监听动画结束进行回调。JS提供了以下事件用于监听动画的结束,简单总结学习下。

CSS3动画监听事件

transitionEnd事件

transitionEnd事件会在CSS transition动画结束后触发。

动画结束后触发监听事件

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}.demo{margin:100px;width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;}.demo:hover{width: 200px;}</style>
</head>
<body><div id="demo" class="demo">鼠标移入</div><script type="text/javascript">var element = document.getElementById('demo')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}</script>
</body>
</html>

事件多次触发问题

当存在多个属性过渡变化时,结束时会多次触发transitionend事件。看个例子:
当过渡结束时,width和background-color都发生变化,会触发两次transionend事件

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}.demo{width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;}.w200{width: 200px;background-color: #fef;}</style>
</head>
<body><div id="demo" class="demo" onmouseover="change()" onmouseout="change()"></div><script type="text/javascript">var element = document.getElementById('demo')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}function change() {element.className = element.className === 'demo' ? 'demo w200': 'demo'}</script>
</body>
</html>

事件失效问题及解决方案

1、在transiton动画完成前设置display:none,事件不会触发。

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}.demo{width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;}.w200{width: 200px;}</style>
</head>
<body><div id="demo" class="demo" onmouseover="change()" onmouseout="change()"></div><script type="text/javascript">var element = document.getElementById('demo')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}function change() {element.className = element.className === 'demo' ? 'demo w200': 'demo'// 500ms后设置display:nonesetTimeout(function (){element.style.display = 'none'},400)}</script>
</body>
</html>

2、当transition完成前移除transition一些属性时,事件也不会触发,例如:

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}.demo{width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;}.noTranstion{width:100px;height: 100px;background-color: #ddc;}.w200{width: 200px;}</style>
</head>
<body><div id="demo" class="demo" onmouseover="change()" onmouseout="change()"></div><script type="text/javascript">var element = document.getElementById('demo')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}function change() {element.className = element.className === 'demo' ? 'demo w200': 'demo'setTimeout(function(){element.className = 'noTranstion'},400)}</script>
</body>
</html>

3、元素从display:none到block,不会有过渡,导致无法触发transitionend事件
例如:元素从display:none 到block opacity从0到1,无法触发过渡效果。

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}body{padding: 50px;}.demo{width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;opacity:0;display: none;}.noTranstion{width:100px;height: 100px;background-color: #ddc;}.opt{display: block;opacity:1}.w200{width: 200px;}button{position: absolute;top: 200px;width: 100px;height: 40px;}</style>
</head>
<body><div id="demo" class="demo" onmouseover="change()" onmouseout="change()"></div><button onclick="change()">Click</button><script type="text/javascript">var element = document.getElementById('demo')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}function change() {element.className = element.className === 'demo' ? 'demo opt': 'demo'}</script>
</body>
</html>

无法触发过渡效果原因:
元素从none到block,刚生成未能即时渲染,导致过渡失效。所以需要主动触发页面重绘,刷新DOM。页面重绘可以通过改变一些CSS属性来触发,例如:offsetTop、offsetLeft、offsetWidth、scrollTop等。
触发过渡效果解决方案:
1、通过定时器延迟渲染

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}body{padding: 50px;}.demo{width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;opacity: 0;display: none;}.opt{display: block;}button{position: absolute;top: 200px;width: 100px;height: 40px;}</style>
</head>
<body><div id="demo" class="demo"></div><button id="button" onclick="change()">点击</button><script type="text/javascript">var element = document.getElementById('demo')var button = document.getElementById('button')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}function change() {element.className = element.className === 'demo' ? 'demo opt': 'demo'if(element.className === 'demo'){element.style.opacity = nullbutton.innerHTML = '点击'}else{setTimeout(function(){element.style.opacity = '1'button.innerHTML = '重置'},10)}}</script>
</body>
</html>

2、强制获取当前内联样式
通过window.getComputedStyle()方法返回应用样式后的元的所有CSS属性的值,并解析这些值可能包含的任何基本计算。也就是说返回的属性值是已计算后的值,即DOM元素的样式已经更新了。然后再改变对应属性值触发过渡效果。例如:

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}body{padding: 50px;}.demo{width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;opacity: 0;display: none;}.opt{display: block;}button{position: absolute;top: 200px;width: 100px;height: 40px;}</style>
</head>
<body><div id="demo" class="demo"></div><button id="button" onclick="change()">点击</button><script type="text/javascript">var element = document.getElementById('demo')var button = document.getElementById('button')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}function change() {element.className = element.className === 'demo' ? 'demo opt': 'demo'if(element.className === 'demo'){element.style.opacity = nullbutton.innerHTML = '点击'}else{// setTimeout(function(){//     element.style.opacity = '1'//     button.innerHTML = '重置'// },10)window.getComputedStyle(element, null).opacityelement.style.opacity = '1'button.innerHTML = '重置'}}</script>
</body>
</html>

3、触发重绘刷新DOM
通过clientWidth触发重绘,例如:

<!DOCTYPE html>
<html>
<head><title>transtionend demo</title><style type="text/css">*{margin:0;padding: 0;}body{padding: 50px;}.demo{width:100px;height: 100px;background-color: #ddc;transition: all 0.5s ease-out;opacity: 0;display: none;}.opt{display: block;}button{position: absolute;top: 200px;width: 100px;height: 40px;}</style>
</head>
<body><div id="demo" class="demo"></div><button id="button" onclick="change()">点击</button><script type="text/javascript">var element = document.getElementById('demo')var button = document.getElementById('button')element.addEventListener('transitionend', handle, false)function handle(){alert('transitionend事件触发')}function change() {element.className = element.className === 'demo' ? 'demo opt': 'demo'if(element.className === 'demo'){element.style.opacity = nullbutton.innerHTML = '点击'}else{// setTimeout(function(){//     element.style.opacity = '1'//     button.innerHTML = '重置'// },10)// window.getComputedStyle(element, null).opacityelement.clientWidth;element.style.opacity = '1'button.innerHTML = '重置'}}</script>
</body>
</html>

浏览器兼容性

移动端基本支持 android2.1+、webkit3.2+
详见浏览器兼容性

animationEnd事件

与transitonend事件类似,详见

Zepto中animate结束回调实现

查看了下zepto动画模块的源代码,animate()方法在动画结束后触发回调也是通过transitionend、animationend事件来触发。
另外在一些低版本的Android手机可能无法触发transitionend事件,需要手动触发。

$.fx = {off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined),speeds: { _default: 400, fast: 200, slow: 600 },cssPrefix: prefix,transitionEnd: normalizeEvent('TransitionEnd'),animationEnd: normalizeEvent('AnimationEnd')}
// 手动触发事件
if (duration > 0){this.bind(endEvent, wrappedCallback)// transitionEnd is not always firing on older Android phones// so make sure it gets firedsetTimeout(function(){if (fired) returnwrappedCallback.call(that)}, ((duration + delay) * 1000) + 25)}

参考链接

zepto动画模块源码
transitionend事件MDN
transtion属性详解MDN
transitionend事件详解
Window.getComputedStyle() 方法

转载于:https://www.cnblogs.com/GeniusLyzh/p/8324811.html

JS如何监听动画结束相关推荐

  1. html5监听动画结束,js判断css动画是否完成 animation,transition

    气死了,发现这些鸟人讲事情都讲一半,害死初学者. css动画有两种,animation,transition,所以分开来讲. 1.animation: css定义 #left1{} html定义: 安 ...

  2. html5监听动画结束,css3动画是否结束监听事件

    css3动画是否结束监听事件: var domObj = $("#id"); domObj [0].addEventListener("webkitAnimationEn ...

  3. js 监听 安卓事件_百行代码实现js事件监听实现跨页面数据传输

    百行代码实现js事件监听实现跨页面数据传输 使用场景 类似消息队列的使用场景,支持同页面和跨页面通信,发送消息和接收消息 技术原理 跨页面通信: 基于事件监听,通过监听 storage事件监听回调机制 ...

  4. html 监听input输入框的值,利用原生JS实时监听input框输入值

    利用原生JS实时监听input框输入值 原生JS中可以使用oninput,onpropertychange,onchange oninput,onpropertychange,onchange的用法 ...

  5. Vue.js:监听属性

    ylbtech-Vue.js:监听属性 1.返回顶部 1. Vue.js 监听属性 本章节,我们将为大家介绍 Vue.js 监听属性 watch,我们可以通过 watch 来响应数据的变化: 实例 & ...

  6. Glide加载webp动画及监听动画播放结束

    Glide加载图片非常方便,使用也非常广泛,但是并不能直接支持webp动图. 可能很多人会使用Fresco来加载webp,但是对于已经使用Glide的项目,总感觉再使用Fresco有点冗余,如果能用G ...

  7. android监听动画完成,android判断动画已结束示例代码

    添加一个动画效果 发现动画没执行完 就直接跳转或者finish掉 添加动画监听事件即可,代码如下: player.startAnimation(anim); anim.setAnimationList ...

  8. 小程序 onPageScroll监听滚动结束

    需求:当用户滑动页面的时候切换品牌的页签缩退,当用户停止滑动的时候页签展示完全 HTML代码: <!-- OnePlus/OPPO的切换 --><viewv-if="cur ...

  9. [转] js对象监听实现

    前言 随着前端交互复杂度的提升,各类框架如angular,react,vue等也层出不穷,这些框架一个比较重要的技术点就是数据绑定.数据的监听有较多的实现方案,本文将粗略的描述一番,并对其中一个兼容性 ...

最新文章

  1. Angular Lazy Load 的一个局限性以及解决办法
  2. php中的fpm_PHP中的FPM是做什么的
  3. 神剑仙缘java_异界修真-神剑仙缘
  4. 九度OJ : 1004 Median
  5. Fisher精确检验的通俗理解
  6. 高斯列主消元法 求非齐次线性方程组 C语言实现代码
  7. iPhone--卡贴是什么
  8. 研究生新生要怎么看论文?
  9. jfinal获取mysql_jfinal 调用mysql结果集-问答-阿里云开发者社区-阿里云
  10. http://jingyan.baidu.com/article/d169e186aa8728436611d8f3.html
  11. MCAFEE杀毒软件无法完全卸载的解决方案
  12. October——I Will Talk
  13. Win10配置pytorch深度学习环境
  14. 05.位图和比较器的简单应用
  15. Ubuntu9.04 mplayer中文字幕乱码解决
  16. 用于编辑计算机程序的语言是,编辑语言
  17. python 实现SMTP发送邮件(四)-添加附件
  18. AI风起荆楚,人工智能中国体系即刻启航
  19. 传统经典CV算法_高斯核函数介绍
  20. 用C语言计算一元二次方程式

热门文章

  1. 基本的MySQL操作
  2. 哈夫曼树的构建、编码以及带权路径长计算
  3. Liveness 探测 - 每天5分钟玩转 Docker 容器技术(143)
  4. vue 项目难点_vue项目中遇到的问题汇总
  5. 正则匹配问号_爬虫之正则表达式
  6. 数据挖掘算法_算法篇(01) 数据挖掘算法初探
  7. 如何在excel中判断某一点在某一区域内_SEM优化师常用的Excel表格函数集合
  8. linux 内核空间占用cpu百分比过高,linux下分析java程序占用CPU、内存过高
  9. php mysql 写法_php 类的写法
  10. 团队行为心理学读书笔记(8)绩效考核背后的行为心理学