在使用JS控制動畫時通常須要在動畫結束後執行回調去進行DOM的相關操做,因此須要監聽動畫結束進行回調。JS提供瞭如下事件用於監聽動畫的結束,簡單總結學習下。javascript
transitionEnd事件會在CSS transition動畫結束後觸發。css
<!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事件html
<!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>
一、在transiton動畫完成前設置display:none,事件不會觸發。java
<!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:none setTimeout(function (){ element.style.display = 'none' },400) } </script> </body> </html>
二、當transition完成前移除transition一些屬性時,事件也不會觸發,例如:android
<!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>
三、元素從display:none到block,不會有過渡,致使沒法觸發transitionend事件
例如:元素從display:none 到block opacity從0到1,沒法觸發過渡效果。css3
<!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等。
觸發過渡效果解決方案:
一、經過定時器延遲渲染git
<!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 = null button.innerHTML = '點擊' }else{ setTimeout(function(){ element.style.opacity = '1' button.innerHTML = '重置' },10) } } </script> </body> </html>
二、強制獲取當前內聯樣式
經過window.getComputedStyle()方法返回應用樣式後的元的全部CSS屬性的值,並解析這些值可能包含的任何基本計算。也就是說返回的屬性值是已計算後的值,即DOM元素的樣式已經更新了。而後再改變對應屬性值觸發過渡效果。例如:github
<!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 = null button.innerHTML = '點擊' }else{ // setTimeout(function(){ // element.style.opacity = '1' // button.innerHTML = '重置' // },10) window.getComputedStyle(element, null).opacity element.style.opacity = '1' button.innerHTML = '重置' } } </script> </body> </html>
三、觸發重繪刷新DOM
經過clientWidth觸發重繪,例如:web
<!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 = null button.innerHTML = '點擊' }else{ // setTimeout(function(){ // element.style.opacity = '1' // button.innerHTML = '重置' // },10) // window.getComputedStyle(element, null).opacity element.clientWidth; element.style.opacity = '1' button.innerHTML = '重置' } } </script> </body> </html>
移動端基本支持 android2.1+、webkit3.2+
詳見瀏覽器兼容性瀏覽器
與transitonend事件相似,詳見
查看了下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 fired setTimeout(function(){ if (fired) return wrappedCallback.call(that) }, ((duration + delay) * 1000) + 25) }
zepto動畫模塊源碼
transitionend事件MDN
transtion屬性詳解MDN
transitionend事件詳解
Window.getComputedStyle() 方法