如何優雅地用原生 JS 寫動畫?相信 WAAPI 能夠幫到您。javascript
Web Animations API ( Web 動畫 API,簡稱 WAAPI )可讓咱們用 JavaScript 寫動畫而且控制動畫。
這些 API 被設計成 CSS Animations 和 CSS Transitions的接口。將來會對這些 API 作補充使其功能更強大,它是對網絡上動畫化的支持最有效的方式之一。
經過 Web 動畫 API ,咱們能夠將交互式動畫從樣式表移動到 JavaScript,將表現與行爲分開。 咱們再也不須要依賴 DOM,如將 CSS 屬性和範圍類寫入元素來控制播放方向。 與純粹的聲明式 CSS 不一樣,JavaScript 還容許咱們動態地將屬性值設置爲持續時間。 對於構建自定義動畫庫和建立交互式動畫,Web 動畫 API 多是完成工做的完美工具。css
簡單實例:WAAPI 實現輪播圖java
當咱們談及網頁動畫時,天然聯想到的是 CSS3 動畫、JS 動畫、SVG 動畫、APNG 動畫等技術以及 jQuery.animate() 等動畫封裝庫,根據實際動畫內容設計去選擇不一樣的實現方式。git
然而,每一個現行的動畫技術都存在必定的缺點,如 CSS3 動畫必須經過JS去獲取動態改變的值,setInterval 的時間每每是不精確的並且還會卡頓,APNG 動畫會帶來文件體積較大的困擾,引入額外的動畫封裝庫也並不是對性能敏感的業務適用。目前情形對開發者而言,魚和熊掌彷佛不可兼得,既但願得到更強大便捷的動畫控制能力,又但願性能和體驗上足夠流暢優雅,若是能有一種瀏覽器原生支持的通用的動畫解決方案,那將是極好極好的呢。github
W3C 提出 Web Animation API(簡稱WAAPI)正緣於此,它致力於集合 CSS3 動畫的性能、JavaScript 的靈活、動畫庫的豐富等各家所長,將盡量多的動畫控制由原生瀏覽器實現,並添加許多 CSS 不具有的變量、控制以及或調的選項。web
Firefox 48+ 和 Chrome 36+ 中提供了對 WAAPI 功能的支持。 Webkit 和 Edge 已經將 WAAPI 移動到各自的待辦事項列表中。能夠在 Can I Use 上查看完整的瀏覽器支持狀況.api
WAAPI 有一個完善且強大的 polyfill 外部庫,使得咱們如今能夠在生產環境下使用它,即使是在瀏覽器受限的狀況下。web-animations.min.js 使 WAAPI 能在絕大部分瀏覽器運行。數組
element.animate( keyframes, AnimationEffectTimingProperties );
keyframes:關鍵幀對象的數組
AnimationEffectTimingProperties:動畫效果屬性的對象瀏覽器
E.g.網絡
document.getElementById("elementId").animate( [ { transform: 'rotate(0)', color: '#000' }, { transform: 'rotate(360deg)', color: '#fff' } ], { duration: 3000, iterations: Infinity } );
WAAPI 的基本語法和 jQuery 的 .animate() 十分類似。但 WWAPI 是瀏覽器原生支持的,不用引入外部庫,在性能上也有很大的優點。接下來咱們一步一步地學習 WAAPI 的用法。
使用 WAAPI,首先要作的是建立一個相似於 CSS3 @keyframes 的關鍵幀對象數組。
E.g. 建立一個輪播圖滑動動畫的關鍵幀對象數組
var slidingLeft = [ //經過 margin-left 和 opacity的漸變來實現簡單滑動 { marginLeft: '0px', opacity: 1 }, { opacity: 0.6, offset: 0.7 }, { marginLeft: "-5rem", opacity: 1 } ];
Web 動畫 API 和 CSS3 動畫的區別:
咱們還須要建立一個動畫效果屬性的對象 ( AnimationEffectTimingProperties object )。
E.g.
var animateOptions = { duration: 1500, easing: 'ease-in-out', }
須要注意的是,AnimationEffectTimingProperties 有一些專業的術語與咱們熟悉的 CSS3 animation 屬性有所不一樣。
下表是二者的對應關係。
AnimationEffectTimingProperties | CSS3 animation 屬性 | 簡述 |
---|---|---|
duration | animation-duration | 規定動畫完成一個週期所花費的秒或毫秒。默認是 0。 |
easing | animation-timing-function | 規定動畫的速度曲線。 |
delay | animation-delay | 規定動畫什麼時候開始。默認是 0。 |
iterations | animation-iteration-count | 規定動畫被播放的次數。默認是 1。 |
direction | animation-direction | 規定動畫是否在下一週期逆向地播放。默認是 'normal' 。 |
fill | animation-fill-mode | 規定動畫在播放以前或以後,其動畫效果是否可見。 |
endDelay | 無對應屬性 | 規定動畫結束後的延遲時間。 |
iterationStart | 無對應屬性 | 規定在迭代過程當中動畫的開始時間點。 |
建立完以上所說的「關鍵幀對象的數組」和「動畫效果屬性的對象」 ,就能夠簡單地啓動一個動畫了。能夠在文章後面查看具體實例。
element.animate( slidingLeft, animateOptions );
咱們想學會如何去控制使用 WAAPI 建立的動畫,仍須要瞭解 Animation 對象。
animate 方法不只僅能讓元素使用動畫,它還有本身的返回值 —— 一個 Animation 對象。經過改變這個對象的屬性和調用它的方法,便可優雅地去控制這個動畫。
var animationObj = element.animate(keyframes, AnimationEffectTimingProperties );
Animation 對象具備的屬性:
屬性名 | 意義 |
---|---|
currentTime | 動畫的當前時間值,以毫秒爲單位。若是缺乏 timeline,則其值爲 null,即表示動畫不活動或還沒有播放。 |
effect | 動畫的目標效果。能夠是基於 AnimationEffectReadOnly 的類型的效果對象,例如 KeyframeEffect 或 null 。 |
finished | 只讀。返回此動畫完成後執行的 Promise 對象。 |
id | 標識動畫的字符串。 |
playState | 只讀。動畫的播放狀態,常見的有 running, paused, finished 。 |
playbackRate | 動畫的播放速度,默認值爲 1。當值爲 0.5 時動畫會減慢一半,當值爲負值時動畫會反向播放 |
ready | 只讀。返回當前動畫準備好播放時執行的 Promise 對象。 |
startTime | 動畫播放開始時的預約時間。默認爲 null。能夠更改此值以使動畫在不一樣的時間開始。 |
timeline | 與當前動畫相關聯的時間軸。默認與文檔的時間軸相同。 |
Animation 對象具備的方法:
方法名 | 用途 |
---|---|
cancel() | 清除由此動畫形成的全部關鍵幀效果,並停止其播放。 |
finish() | 將當前播放時間設置爲與當前播放方向相對應的動畫結束時間。若爲正常播放,則把當前播放時間設置爲動畫總時長;若爲反向播放則把當前播放時間設置爲0。 |
pause() | 暫停播放動畫 |
play() | 開始或繼續播放動畫。若是動畫已完成,則再次開始播放動畫。 |
reverse() | 將動畫的播放方向反轉。若是在未播放的動畫上調用,動畫將從結尾向開頭反向播放。 若是對暫停中的動畫進行了調用,動畫將向反方向繼續播放。一樣的效果能夠經過設置 playbackRate *= -1; 來實現 |
Animation 對象的事件處理程序(回調函數):
WWAPI 支持使用 event 和使用 Promise 兩種方式來處理事件。
下面是兩種 event :
E.g. 若是一個動畫被取消了,移除其元素。
animation.oncancel = animation.effect.target.remove();
Promise
Promise 對象用於一個異步操做的最終完成(或失敗)及其結果值的表示。
animation 對象的 ready 和 finished 屬性會返回一個 Promise 對象,分別對應在動畫準備播放和播放結束的時候。下面是一個使用 Promise 來處理事件回調的示例:
myAnimation.finished.then(() => element.remove())
document.getAnimations() 方法返回當前有效的全部Animation對象的數組,此數組包括CSS Animation,CSS Transition 和 Web Animation。
在較新版本的 Chrome 瀏覽器的開發者工具(F12)的 console drawer 中還能查看頁面中全部的 Animation,包括用 CSS3 定義的動畫:
看懂了上面提到的知識,咱們就可使用 WWAPI 來實現一個簡單的輪播圖,點擊打開 codepen 預覽並查看完整代碼。
JS 部分代碼:
var indexBody = document.querySelector(".index_body"); var btnLeft = document.querySelector(".left_btn"); var btnRight = document.querySelector(".right_btn"); var slideBox = document.querySelector('.slidebox'); var items = slideBox.getElementsByClassName("slide_item"); //使用web animations建立動畫,左滑和右滑共用一個動畫 var slidingLeft = [ {marginLeft: '0px', opacity: 1}, {opacity: 0.6, offset: 0.7}, {marginLeft: "-5rem", opacity: 1} ]; var sliding = slideBox.animate( slidingLeft, { duration: 1500, easing: 'ease-in-out', } ); sliding.onfinish = function(){ slideBox.style.marginLeft = '0px'; if(sliding.playbackRate != -1){ slideBox.appendChild(items[0]); } btnRight.onclick = slideRight; btnLeft.onclick = slideLeft; }; function slideRight(){ sliding.playbackRate = 1; //切換滑動方向爲右 sliding.play(); btnLeft.onclick = null; btnRight.onclick = null; // console.log(sliding.effect); }; function slideLeft(){ slideBox.insertBefore(items[items.length - 1],items[0]); slideBox.style.marginLeft = '-5rem'; sliding.playbackRate = -1; //切換滑動方向爲左 sliding.play(); btnLeft.onclick = null; btnRight.onclick = null; }; btnRight.onclick = slideRight; btnLeft.onclick = slideLeft; //自動滑動 var slideTimer = setInterval(() => { btnRight.click(); },3000); //鼠標懸停時中止滑動 indexBody.onmouseover = function(){ clearInterval(slideTimer); }; //鼠標離開時繼續自動滑動 indexBody.onmouseout = function(){ slideTimer = setInterval(() => { btnRight.click(); },3000); };
web-animations 官方的 demo 很是適合初接觸WAAPI的同窗做爲開始的範例。
另外推薦一個挺炫酷的動畫庫 —— Animista,上面有不少用 CSS3 實現的動畫(可在線查看代碼,主要是 keyframes ),咱們能夠嘗試用 WWAPI 來實現一樣的動畫效果。