【第974期】WAAPI
前言
看到WAAPI,默默的打開了搜索,原來是它。今日早讀文章由@阿成翻譯投稿。
正文從這開始~
WAAPI 讓我們能夠構建動畫並控制動畫的播放。WAAPI 就是Web Animations API。
認識 Web Animations API
WAAPI 向開發者開放了瀏覽器的動畫引擎,開發者可以通過 Javascript 介面來操作該引擎。該 API 是基於 CSS 動畫和 CSS 過渡實現的,並且考量了未來可能會增加的動畫效果。它是 web 平台支持的實現動畫的最高效的方式之一,在該方式下瀏覽器能夠進行內部優化,因而不再需要所謂的黑科技、強制性的技巧和 requestAnimationFrame 方法。
通過 WAAPI,我們可以很大程度上將交互動畫從樣式轉移到 JS 上,將行為與表現分離。我們不再需要依賴很多的 DOM 技巧來控制動畫的播放,比如直接賦值 CSS 屬性或者切換類型。並且與簡單、聲明式的 CSS 不同,JS 允許我們動態地改變樣式屬性或播放選項。對需要構建自定義動畫庫和開發動畫介面的開發者來說,WAAPI 可能是最酷的工具了。讓我們來看看它都可以做什麼。
瀏覽器支持
不多說,直接上 can i use。 http://caniuse.com/#search=web%20animations%20api
用 WAAPI 來寫 CSS 動畫
對大多數 Web 開發者來說,CSS 動畫是我們很熟悉的東西,因此學習 WAAPI 最好的方式莫過於從 CSS 動畫開始。CSS 動畫有著與 WAAPI 相似的語法,因此很適合作為我們講解的開始。
CSS 版本
這是一個翻跟頭(wut?)的動畫,用 CSS 編寫的,表現了愛麗絲墜入兔子洞從而進入仙境的場景(要看完整的代碼請點擊codepen):
GIF/1191K
我們觀察到背景的移動,愛麗絲的旋轉以及她身體顏色隨著旋轉產生的變化。我們這裡只關注愛麗絲自身旋轉的動畫。這是一份簡單的 CSS 實現:
#alice{
animation:aliceTumbling infinite 3s linear;
}
@keyframes aliceTumbling{
%{
color:#000;
transform:rotate()translate3D(-50%,-50%,);
}
30%{
color:#431236;
}
100%{
color:#000;
transform:rotate(360deg)translate3D(-50%,-50%,);
}
}
這段代碼的效果就是讓愛麗絲身體的顏色和她自身的旋轉以恆定的速率每3s完成一個循環。在 @keyframes 代碼中我們可以看到,在動畫進行到 30% 的時候,愛麗絲身體的顏色從黑色變成了深紫紅色,隨後 70% 的時間裡,有逐漸變回黑色。
JS 版本
現在讓我們嘗試一下,通過 WAAPI 來完成相同的動畫。
刻畫關鍵幀
首先我們需要創建與 CSS 關鍵幀一致的關鍵幀數組:
varaliceTumbling=[
{transform: rotate(0) translate3D(-50%, -50%, 0) ,color: #000 },
{color: #431236 ,offset:0.333},
{transform: rotate(360deg) translate3D(-50%, -50%, 0) ,color: #000 }
];
這裡我們使用了一個包含很多關鍵幀對象的數組。與 CSS 不同的是,WAAPI 不需要你通過百分比去指定每一幀發生的時間點,WAAPI 會自動將動畫按照你定義的關鍵幀數量等分。這意味著一個關鍵幀數組如果包含了三個關鍵幀,中間的關鍵幀將呈現在整個動畫過程的 50% 處。
當我們想明確地設置某一幀的呈現時間時,可以直接在這一幀的對象中指定一個 offset 屬性。在上面的例子中,為了確保愛麗絲身體的顏色在 30% 而不是 50% 的位置變成深紫紅色,我們將這一幀的 offset 設置為 0.333。
顯然,每一個動畫過程必須包含兩個或兩個以上的關鍵幀,如果只定義了一個關鍵幀,WAAPI 會拋出一個 NotSupportedError 異常。
總結一下,除非你設置 offset 屬性,否則動畫過程會按照幀數等分。
配置時序屬性
這裡我們需要參照上面的 CSS 動畫創建一個包含時序屬性的對象(可以看作是 AnimationEffectTimingProperties 的一個實例)
varaliceTiming={
duration:3000,
iterations:Infinity
}
你可能會注意到,這裡與 CSS 動畫時序等價的 JS 時序表達有些許的不同:
duration 是以 mm(毫秒) 為單位的。
iterations 對應於 CSS 中的 iteration-count
PS:其實 CSS 動畫和 WAAPI 之間還有很多小的差異。比如說,WAAPI 不使用 infinite 字元串,而是使用 JS 中的關鍵字 Infinity。不使用 animation-timing-function 而是使用 easing。CSS 動畫中 animation-timing-function 的默認值是 ease,而在 WAAPI 中,默認值是 linear。
組合一下
現在是時候把這兩個配置用 Element.animate() 方法組合起來了:
document.getElementById("alice").animate(
aliceTumbling,
aliceTiming
)
動畫效果在這裡
animate() 方法可以在任何的 DOM 元素上調用,CSS 能完成的 WAAPI 都可以完成。
還有,如果我們只想指定 duration 屬性,可以直接傳一個數字值:
document.getElementById("alice").animate(
[
{transform: rotate(0) translate3D(-50%, -50%, 0) ,color: #000 },
{color: #431236 ,offset:0.333},
{transform: rotate(360deg) translate3D(-50%, -50%, 0) ,color: #000 }
],3000);
使用 play(), pause(), reverse() 和 playbackRate 控制播放
現在我們已經能用 WAAPI 寫 CSS 動畫了,不過,WAAPI 真正強大的地方在於,控制動畫的播放。WAAPI 為此提供了幾個非常有用的方法。讓我們通過下面的愛麗絲變大變小動畫來看一看如何暫停和播放動畫(要看完整的代碼請點擊codepen):
GIF/569K
在這個遊戲中,我們通過瓶子里的藥水使愛麗絲變小,通過蛋糕使愛麗絲變大。
暫停和播放動畫
我們過會兒再討論愛麗絲的動畫,現在我們先來看蛋糕的動畫:
Element.animate() 方法調用後將立即運行。為了給玩家一個點擊蛋糕的機會,而不是讓蛋糕自己消失掉,我們在 Element.animate() 方法之後立即調用 Animation.pause() 方法:
nommingCake.pause();
之後我們可以用 Animation.play() 方法在適當的時機播放動畫:
nommingCake.play();
這裡我們想把蛋糕的動畫跟愛麗絲的動畫聯繫起來,愛麗絲吃了蛋糕後變大。可以通過如下函數實現:
vargrowAlice=function(){
// Play Alice s animation.
aliceChange.play();
// Play the cake s animation.
nommingCake.play();
}
當用戶在蛋糕上按下滑鼠或者用手指按蛋糕時,我們就可以調用上面的 growAlice 函數來播放動畫:
cake.addEventListener("mousedown",growAlice,false);
cake.addEventListener("touchstart",growAlice,false);
PS:當然,你得在用戶抬起滑鼠或手指時,暫停播放動畫,不然...
其他有用的方法
除了暫停和播放,我們還可以用一下的方法:
Animation.finish() 跳過動畫過程,直接跳到動畫的結束位置。
Animation.cancel() 取消動畫過程,直接跳到動畫的開始位置。
Animation.reverse() 設置動畫的 playbackRate 屬性為負值,即回放動畫。
讓我們先看一下 playbackRate 這個屬性,一個負的 playbackRate 屬性會導致動畫以相反的方向播放。當愛麗絲喝了藥水,她就變小了。這是因為喝下藥水的函數將 playbackRate 從 1 變成 -1:
varshrinkAlice=function(){
aliceChange.playbackRate=-1;
aliceChange.play();
}
bottle.addEventListener("mousedown",shrinkAlice,false);
bottle.addEventListener("touchstart",shrinkAlice,false);
在 鏡中緣 情節中,愛麗絲來到了另一個世界,在這個世界中,她必須奔跑才能保持在原地,奔跑得更快才能前進。在下面這個 「跟紅皇后比賽」 的例子中,愛麗絲和紅皇后奔跑以使自己保持在原地(要看完整的代碼請點擊codepen):
GIF/144K
因為身體變小很容易累,愛麗絲會不斷地慢下來。我們可以通過如下代碼減小動畫的 playbackRate 屬性:
setInterval(function(){
if(redQueen_alice.playbackRate>.4){
redQueen_alice.playbackRate*=.9;
}
},3000);
但是我們要允許用戶通過點擊使動畫加速,這可以通過擴大動畫的 playbackRate 屬性來完成:
vargoFaster=function(){
redQueen_alice.playbackRate*=1.1;
}
document.addEventListener("click",goFaster);
document.addEventListener("touchstart",goFaster);
當你點擊的時候,背景中的物體也會受到影響。當你讓愛麗絲和紅皇后的速度快一些時會發生什麼呢?慢一些時呢?
獲取動畫的信息
想想我們還可以如何利用 playbackRate 屬性。比如通過允許放慢整個網站的動畫速率來提高前庭功能障礙患者的可訪問性。通過 CSS 來完成這項功能是不可能的,除非重新計算每個 CSS 動畫規則中的 duration 屬性。而通過 WAAPI,我們可以用即將到來的 document.getAnimations() 方法遍歷頁面中的每個動畫並調整它們的 playbackRate 屬性:
document.getAnimations().forEach(
function(animation){
animation.playbackRate*=.5;
}
);
瞧,使用 WAAPI 的話,你需要做的全部就是改變一個數值而已。
另一個 CSS 動畫難以獨自完成的事情是,創建依賴於另一個動畫的動畫。舉個例子,在愛麗絲變大變小的代碼中,你可能注意到了這個奇怪的 duration 屬性:
為了理解這樣寫的原因,讓我們看看愛麗絲動畫的代碼:
varaliceChange=document.getElementById( alice ).animate(
[
{transform: translate(-50%, -50%) scale(.5) },
{transform: translate(-50%, -50%) scale(2) }
],{
duration:8000,
easing: ease-in-out ,
fill: both
});
愛麗絲的動畫是從原來身體大小的一半變成原來身體大小的兩倍。我們先在動畫開始的地方暫停:
aliceChange.pause();
現在她只有原來身體一半的大小,看起來就像已經喝下了整瓶的藥水。我們想要的是,一開始身體處在正常的大小,這就需要動畫過程已經進行到50%的位置。我們可以通過設置 Animation.currentTime 為 4000 來解決這個問題:
aliceChange.currentTime=4000;
在製作整個動畫的過程中,我們可能需要多次修改這個值以達到最好的效果。如果能自動地設置這個值就好了,這樣我們就不需要每次手動編輯了。實際上我們可以通過引用 Animation.effect 屬性來完成這件事,它返回一個包含當前動畫所有細節的對象:
我們也可以用同樣的方式設置蛋糕和藥水動畫的 duration 屬性:
現在三個動畫都鏈接到同一個 duration,我們每次只需要修改一處就可以了。
varendGame=function(){
// get Alice s timeline s playhead location
varalicePlayhead=aliceChange.currentTime;
varaliceTimeline=aliceChange.effect.activeDuration;
// stops Alice s and other animations
stopPlayingAlice();
// depending on which third it falls into
varaliceHeight=alicePlayhead/aliceTimeline;
if(aliceHeight
// Alice got smaller!
...
}elseif(aliceHeight>=.666){
// Alice got bigger!
...
}else{
// Alice didn t change significantly
...
}
}
Callbacks and promises
CSS 動畫和 CSS 過渡都有它們自己的事件監聽,同樣地,WAAPI 也有:
onfinish 用於註冊完成事件,並且可以通過 finish() 方法手動觸發
oncancel 用於註冊取消事件,並且可以通過 cancel() 方法手動觸發
這裡我們為蛋糕、藥水和愛麗絲註冊完成事件,事件處理器指定為 endGame 函數:
// When the cake or runs out...
nommingCake.onfinish=endGame;
drinking.onfinish=endGame;
// ...or Alice reaches the end of her animation
aliceChange.onfinish=endGame;
未來會針對這兩個事件增加對 promise 的支持。
結論
以上介紹的是 WAAPI 的基本特性,大多數都已經被現代瀏覽器所支持。現在你應該已經準備好了在瀏覽器中進行一番探索,創造出你自己的動畫!
關於本文
譯者:@阿成
譯文:https://github.com/aimergenge/Web-Notes/blob/master/JS/WAAPI.md
文中提到 can i use,目前@小志開發了一個簡易版小程序,有興趣的可以搜索:
CanIuse簡化版


※上海一條視頻招前端開發
※掌握 HTTP 緩存——從請求到響應過程的一切(上)
※【圖書】深入理解ES6
※HTML5動畫與動效之四
※「大產品小細節」5分鐘了解費茨定律
TAG:前端早讀課 |
※儀錶不凡97490110歐米茄OMEGA日月星辰 吾的最愛
※2017年全國居民人均可支配收入達25974元 CPI上漲
※報廢廠里的老夥計——1974復古124 Sport Spider
※江蘇人口超132萬的大區 GDP竟超974.81億
※腕美再現97490112:xf最近推出一款計時機械的沛納海pam519
※恆指半日跌0.48%報29748點 金誠控股跌66.6%
※1950、1962、1974、1986、1998、2010年屬虎人今年運程
※屬虎的2018下半年運勢 1950,1962,1974,1986,1998,2010
※1950,1962,1974,1986,1998,2010虎的人2018年運程
※1974雋永老虎黃塗裝回歸,川崎 Z900 RS 2020款最新配色
※腕美再現97490112
※卡拉什尼科夫1974AK-74突擊步槍
※腕美再現97490112:機械錶通常可分為下列兩種
※1974年屬虎的人2019年運勢
※1974年的小楷字帖,售價0.12元,俊美!
※男命1974年10月1號戌時出生,問2018年財運如何?
※1974年的小楷字帖,售價0.12元,真俊!
※生肖運勢:1974年屬虎的人2019年運程
※儀錶不凡97490110:歐米茄1948到底有何迷人魅力
※1974年2月22日 毛澤東提出劃分三個世界的理論