當咱們談及網頁動畫時,天然聯想到的是 CSS3 動畫、JS 動畫、SVG 動畫 等技術以及 jQuery.animate() 等動畫封裝庫,根據實際動畫內容設計去選擇不一樣的實現方式,然而,每一個現行的動畫技術都存在必定的缺點,如 CSS3動畫必須經過JS去獲取動態改變的值,一個動畫效果分散在css文件和js文件裏很差維護,setInterval 的時間每每是不精確的並且還會卡頓,引入額外的動畫封裝庫也並不是對性能敏感的業務適用。javascript
Web Animation API 的歷史也應該有幾年了,可是每當作動畫效果時,筆者就是依賴各類庫,不多想着去原生實現,最終形成了咱們的項目各類依賴庫,體積也不斷變大,性能如何也不得而知,做爲前端開發的咱們多麼但願原生的JS去支持通用的動畫解決方案, Web Animation API 可能就是一個不錯的解決方案。css
W3C 提出 Web Animation API(簡稱 WAAPI)正緣於此,它致力於集合 CSS3 動畫的性能、JavaScript 的靈活、動畫庫的豐富等各家所長,將盡量多的動畫控制由原生瀏覽器實現,並添加許多 CSS 不具有的變量、控制以及或調的選項。它爲咱們提供了一種通用語言來描述DOM元素的動畫,主要方法有:Animation,KeyframeEffect,AnimationEvent,DocumentTimeline,EffectTiming。關於這個API的詳細介紹,能夠參照MDN的這篇文檔,連接地址:developer.mozilla.org/en-US/docs/…html
使用Web Animations API,咱們能夠將交互式動畫從樣式表移動到JavaScript,將表示與行爲分開。咱們再也不須要依賴DOM的技術,例如編寫CSS屬性做用於元素以控制方向。爲了構建自定義動畫庫和建立交互式動畫,Web Animations API多是完成工做的完美工具,你無需藉助第三方動畫庫,就能夠輕鬆實現一個效果不錯的動畫。前端
爲了讓你們對這個API有個清晰的認識,筆者在接下來的系列文章裏,用五六個例子讓你們理解這個API,今天筆者將用此API實現一個隨機移動的圖片開始進行介紹,好比用這個效果咱們能夠製做一個隨機飄浮移動的廣告位,遊戲裏隨機走動的怪物等等,本例中的特色就是爲了體現Web Animation API的靈活性和強大性,我沒有引用任何第三方類庫,好比(JQ)以及也沒有使用setTimeout和requestAnimationFrame()函數。java
本篇文章預計時間 5 分鐘git
開始前,咱們先來看看完成後的動畫效果,示例以下效果:github
不管圖片怎麼隨機移動,咱們都但願在指定的容器裏,而不是漫無邊際,首先咱們在html頁面定義容器:web
<div id="container"> </div>複製代碼
接下來定義容器的樣式:數組
body { margin: 0; } div#container { height:500px; width:100%; background: #C6CEF7; } #target { position: absolute; filter: drop-shadow(-12px 12px 7px rgba(0,0,0,0.5)); }複製代碼
var container = document.getElementById("container");複製代碼
爲了更加直觀性,我選擇一個走動的gif圖片,因爲圖片的加載須要一些時間,爲了避免破壞動畫的連貫性,確保圖片加載完了咱們在執行動畫,相關代碼以下:瀏覽器
var target = document.createElement("img");
target.id = "target";
target.onload = function() {
floatHead();
}
target.src = "walk.gif";
container.appendChild(target);複製代碼
你們都看到了,onload部分咱們加載了floatHead()函數,接下來咱們來進行相關實現,此函數主要包含如下功能:建立一個隨機位置,計算移動時間,封裝移動動畫。
咱們利用Math.floor函數實現了其隨機位置的變化,示例代碼以下:
function makeNewPosition() {
var containerVspace = container.offsetHeight - target.offsetHeight,
containerHspace = container.offsetWidth - target.offsetWidth,
newX = Math.floor(Math.random() * containerVspace),
newY = Math.floor(Math.random() * containerHspace);
return [newX, newY];
}複製代碼
這裏的隨機位置,咱們返回了一個數組,描述的是圖片相對容器的位置,即top,left。這裏你須要理解offsetHeight,offsetWidth,可理解爲div的可視高度或寬度,樣式的height或Width+上下padding或左右padding+上下border-width或左右border-width。
動畫是有時間屬性的,咱們進行位置的移動,須要花多久時間,假設運動速度爲0.1個單位/毫秒。這個函數包含兩個數組:prev爲當前目標的原始X和Y位置,next爲移動目標的位置。此函數沒有進行進行精確的距離計算,只是判斷了x和y軸上移動的距離大小用最大的距離除以速度,示例代碼以下:
function velocity(prev, next) {
var x = Math.abs(prev[1] - next[1]),
y = Math.abs(prev[0] - next[0]),
larger = x > y ? x : y,
speedModifier = 0.1,
time = Math.ceil(larger / speedModifier);
return time;
}複製代碼
接下來是咱們Web Animations API的核心部分,咱們使用其核心API在加上上述咱們完成的兩個函數讓其動起來,示例代碼以下:
function floatHead() {
var newPos = makeNewPosition(),
oldTop = target.offsetTop,
oldLeft = target.offsetLeft,
target.animate([
{ top: oldTop+"px", left: oldLeft+"px" },
{ top: newPos[0]+"px", left: newPos[1]+"px" }
], {
duration: velocity([oldTop, oldLeft],newPos),
fill: "forwards"
}).onfinish = function() {
floatHead();
}
}複製代碼
該Animation的animate函數有兩個參數,一個是KeyframeEffects數組和AnimationEffectTimingPropertiesoptions 的對象。基本上,第一個參數映射到您將放入CSS中的內容@keyframes,你能夠想象成css中的@keyframes內容,好比如下代碼:
@keyframes emphasis {
0% {
transform: scale(1);
opacity: 1;
}
30% {
transform: scale(.5);
opacity: .5;
}
78.75% {
transform: scale(.667);
opacity: .667;
}
100% {
transform: scale(.6);
opacity: .6;
}
}複製代碼
你能夠將「{}」裏的信息順序依次放到一個數組裏;第二個參數是時間控制 timing,包括有 duration 持續時間、iterations 執行次數、direction 動畫方向、easing 緩動函數等屬性。好比如下代碼:
#toAnimate {
animation: emphasis 700ms ease-in-out 10ms infinite alternate forwards;
}複製代碼
你還可能注意到咱們使用了onfinish事件完成了floatHead函數的反覆調用,其是Animation的屬性,監聽動畫完成事件,若是動畫完成繼續執行floatHead(),至關不斷的遞歸調用。
<!DOCTYPE html> <html lang="en"> <head> <style> body { margin: 0; } div#container { height:500px; width:100%; background: #C6CEF7; } #target { position: absolute; filter: drop-shadow(-12px 12px 7px rgba(0,0,0,0.5)); } </style> <meta charset="UTF-8"> <title>前端達人示例展現——圖片隨機移動</title> </head> <body> <div id="container"></div> <script> function makeNewPosition() { var containerVspace = container.offsetHeight - target.offsetHeight, containerHspace = container.offsetWidth - target.offsetWidth, newX = Math.floor(Math.random() * containerVspace), newY = Math.floor(Math.random() * containerHspace); return [newX, newY]; } function velocity(prev, next) { var x = Math.abs(prev[1] - next[1]), y = Math.abs(prev[0] - next[0]), larger = x > y ? x : y, speedModifier = 0.2, time = Math.ceil(larger / speedModifier); return time; } function floatHead() { var newPos = makeNewPosition(), oldTop = target.offsetTop, oldLeft = target.offsetLeft; target.animate([ { top: oldTop+"px", left: oldLeft+"px" }, { top: newPos[0]+"px", left: newPos[1]+"px" } ], { duration: velocity([oldTop, oldLeft],newPos), fill: 'forwards' }).onfinish = function() { floatHead(); } } var container = document.getElementById("container"), target = document.createElement("img"); target.id = "target"; target.onload = function() { floatHead(); } target.src = "walk.gif"; target.width="200"; container.appendChild(target); </script> </body> </html>複製代碼
最後聊聊你關心的各瀏覽器兼容問題,以下所示顯示了各個瀏覽器的兼容狀況:
看來好多都是部分支持,沒有徹底支持,筆者也親自測試了下,在pc端最新版的谷歌瀏覽器和Firefox是沒有任何問題的能夠完美運行,筆者的safari仍是運行不起來,在iPhone XS Max沒法運行。
做爲一名前端開發者,在移動端大行其道怎麼能容忍在手機端沒有效果,爲了在現代瀏覽器廠商還沒徹底跟進到位的時候搶先用上 WAAPI(Web Animation API簡稱),咱們能夠選擇引入針對 Web Animation API 的 Polyfill 庫 [github.com/web-animati…],從而在 IE/Firefox/Safari 等瀏覽器上體驗到 WAAPI 的精彩。
所以咱們只須要文件裏引入如下js,就能夠完美體驗:
<script src="https://cdn.jsdelivr.net/web-animations/latest/web-animations.min.js"> </script>複製代碼
移動端瀏覽器,Android 5.0 以上的 Android Browser 和 Chrome for Android 自己就已經支持 WAAPI 了,加上 Polyfill 以後,筆者的手機終於能夠看到運行效果了,微信裏的QQ內核瀏覽器也能完美運行,pc端的safari也能夠完美運行。能夠說是全平臺支持了,有了這個庫你能夠放心大膽的使用了。
好了今天的代碼擼完了,js代碼還不到50行(注:爲了在手機端運行,引入了web-animations.min.js),您能夠點擊"www.qianduandaren.com/demo/walk/"行預覽,筆者親測在iPhone XS Max運行良好,其餘手機沒有,有待親們的測試,歡迎到留言區告知。下一篇文章咱們用不到20行的原生js代碼純手工擼一個漂亮的時鐘,敬請期待。
更多精彩內容,請微信關注「前端達人」公衆號!