始發於個人博客 ryougifujino.com,歡迎訪問留言。javascript
CSS Animations 的出現讓你在文檔和應用上建立難以想象的動畫效果成爲了可能。可是,有一些你想實現的東西可能並不是如此淺顯,或者說你不能輕易的想出一種聰明的方式來完成它們。這篇文章包含了一系列的提示與技巧來使得你的工做更加容易,其中包括瞭如何讓一個已經中止的動畫從新運行起來。css
CSS Animations 的規範沒有提供讓動畫再次運行起來的方法。並不存在適用於元素的魔法方法requestAnimation()
,甚至即便你把元素的animation-play-state
設置爲"running"
也無濟於事。你得用一種聰明的技巧來使得已經中止的動畫再次回放。html
咱們將介紹一種咱們認爲足夠穩定可靠的方法給你。java
首先,讓咱們建立一個用於執行動畫的<div>
和一個用於播放(或者說回放)動畫的按鈕。ide
<div class="box">
</div>
<div class="runButton">Click me to run the animation</div>
複製代碼
如今讓咱們用CSS定義動畫自己。一些並不重要的CSS(例如播放按鈕自身的樣式)出於簡潔的考慮並不會在這裏出現。函數
@keyframes colorchange {
0% { background: yellow }
100% { background: blue }
}
.box {
width: 100px;
height: 100px;
border: 1px solid black;
}
.changing {
animation: colorchange 2s;
}
複製代碼
這裏有兩個 class。"box"
class 是盒子外觀的基礎描述,並不包含任何動畫信息。動畫細節都被包含在"changing"
class 裏,它描述了:一個叫colorchange
的@keyframes
將會被運用在一個2秒鐘的做用於盒子的動畫過程之中。動畫
下一步咱們將看看 JavaScript 所作的工做。這項技術的核心位於play()
函數之中,這個函數將在用戶點擊「Run」按鈕時被回調。ui
function play() {
document.querySelector(".box").className = "box";
window.requestAnimationFrame(function(time) {
window.requestAnimationFrame(function(time) {
document.querySelector(".box").className = "box changing";
});
});
}
複製代碼
看起來真的很奇怪,不是嗎?這是由於再次播放動畫的惟一方法就是刪除動畫效果,讓文檔從新計算樣式來使得它明白你已經進行了刪除,而後再把動畫效果添加回元素中。爲了讓這一切發生,咱們必需要有創造性。spa
這是當play()
方法被調用時發生了什麼:.net
class
被重置爲了"box"
。這個動做把其餘當前運用在盒子上的 class 都給刪除了,包括處理動畫的"changing"
class。換而言之,咱們正把盒子上的動畫效果給移除掉。可是,在樣式從新計算完成以前,或反應改變的刷新發生以前,class 列表的變動都不會生效。window.requestAnimationFrame()
來指定一個回調。這樣咱們的回調就會在文檔下一次重繪以前執行。問題在於,由於是發生重繪前的,因此樣式的重計算尚未真的發生!因此……requestAnimationFrame()
!這一次,回調運行於第二次下一次重繪以前,這時第一次重繪已經完成,因此能夠確保樣式的重計算已經發生。這個回調把changing
class 添加回了盒子之上,使得重繪後動畫將再次開始。固然,咱們還須要給咱們的"Run"按鈕添加一個事件處理器:
document.querySelector(".runButton").addEventListener("click", play, false);
複製代碼
僅僅刪除應用於元素的animation-name
就會讓元素跳轉到它的下一個狀態。若是你想在動畫完成時再讓它中止,那麼你可能須要嘗試另外一種不一樣的方法。主要技巧以下:
animation-direction: alternate
。取而代之,你應該顯式地寫一個 keyframe 動畫來模擬這個過程。animationiteration
事件發生時,用 JavaScript 清理正在被使用的動畫。下面的 demo 展現瞭如何實現上述的 JavaScript 技術:
.slidein {
animation-duration: 5s;
animation-name: slidein;
animation-iteration-count: infinite;
}
.stopped {
animation-name: none;
}
@keyframes slidein {
0% {
margin-left: 0%;
}
50% {
margin-left: 50%;
}
100% {
margin-left: 0%;
}
}
複製代碼
<h1 id="watchme">Click me to stop</h1>
複製代碼
let watchme = document.getElementById('watchme')
watchme.className = 'slidein'
const listener = (e) => {
watchme.className = 'slidein stopped'
}
watchme.addEventListener('click', () =>
watchme.addEventListener('animationiteration', listener, false)
)
複製代碼
原文地址(MDN) 更新於Mar 23, 2019, 6:23:51 PM。部分live demo不能連接過來,請前往原文進行查看。