使用Web Animations API建立炫酷動畫

如何優雅地用原生 JS 寫動畫?相信 WAAPI 能夠幫到您。javascript

11-23-54.jpg

Web Animations API

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 能在絕大部分瀏覽器運行。數組

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 動畫的區別:

  • WAAPI 不須要明確地告知每一個關鍵幀出現的時刻在動畫中的百分比,它將根據您給出的關鍵幀數量自動將動畫劃分爲相等的部分。當咱們想要明確地設置一個關鍵幀與其餘關鍵幀的偏移量時,咱們能夠直接在對象中指定一個偏移量( offset:大小範圍是 0 ~ 1 )。
  • WAAPI 的關鍵幀對象中,須要使用元素屬性的駝峯寫法,例如對應 CSS 的屬性 "margin-Left" , WAAPI 的關鍵幀對象要使用 "marginLeft" 。
  • WAAPI 必須至少指定兩個關鍵幀( 表示動畫序列的開始和結束狀態 )。若是您的關鍵幀對象數組只有一個對象成員, Element.animate() 將拋出不支持的異常報錯。

動畫效果屬性的對象

咱們還須要建立一個動畫效果屬性的對象 ( 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 無對應屬性 規定在迭代過程當中動畫的開始時間點。
  • easing 的默認值是 linear,而 animation-timing-function 的默認值是 ease。在使用 WAAPI 時應使用恰當的 easing ,以避免讓動畫變得機械和乏味( 默認的 linear 表示動畫從頭至尾的速度是相同的 )。
  • animation-iteration-count 對應的是 iterations。若是你想要讓動畫一直重複下去,請使用 Infinity 代替 infinite。注意 Infinity 不須要使用逗號包裹,它是 JavaScript 的一個關鍵字,而其餘值是字符串。
  • 時間單位使用 ms 替代了 s,這對於寫過 JavaScript 的開發者來講會更容易接受。( 實際上在 CSS 動畫中也可以使用 ms,不過基本沒人會這樣用。)
  • endDelay 表示動畫結束後的延遲時間,與 delay 的默認值都爲0。若是要將多個動畫串在一塊兒,可是但願在一個動畫的結尾和任何後續動畫的開始之間存在時間間隔,就可使用 endDlay。
  • iterationStart 表示在迭代過程當中動畫的開始時間點。E.g. 若是 iterations 設置爲 1,而且 iterationStart 設置爲 0.5,動畫將從中間開始播放到動畫結尾,而後從動畫開頭開始,結束於中間。而若是將 iterations 和 iterationStart 都設置爲 0.5,動畫將從中間開始播放到結尾就結束了。

建立完以上所說的「關鍵幀對象的數組」和「動畫效果屬性的對象」 ,就能夠簡單地啓動一個動畫了。能夠在文章後面查看具體實例。

element.animate( slidingLeft, animateOptions );

咱們想學會如何去控制使用 WAAPI 建立的動畫,仍須要瞭解 Animation 對象。

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 :

  • oncancel :定義動畫被取消時或執行 cancel() 時觸發的回調函數。
  • onfinish :定義動畫天然完成播放時或執行finish() 時觸發的回調函數。

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 定義的動畫:
image.png

WAAPI 實例 —— 輪播圖

看懂了上面提到的知識,咱們就可使用 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 來實現一樣的動畫效果。

參考資料

相關文章
相關標籤/搜索