前言
說動前端動畫css js讓gif循環(huán)播放,我們熟知的有兩種
CSS 動畫(// + 屬性改變) 動畫
當(dāng)然有人可能會說動畫,從運(yùn)動本質(zhì)了還是第二種。
今天說的是第三種Web API[1], 也有簡稱為WAAPI的。
與純粹的聲明式CSS不同,還允許我們動態(tài)地將屬性值設(shè)置為持續(xù)時間。對于構(gòu)建自定義動畫庫和創(chuàng)建交互式動畫,Web動畫API可能是完成工作的完美工具。
舉兩個栗子落球
點(diǎn)擊之后,球體下落
.gif
const?ballEl?=?document.querySelector(".ball");
ballEl.addEventListener("click",?function?()?{
????????????let?fallAni?=?ballEl.animate({
????????????????transform:?['translate(0,?0)',?'translate(20px,?8px)',?'translate(50px,?200px)']
????????????},?{
????????????????easing:?"cubic-bezier(.68,.08,.89,-0.05)",
????????????????duration:?2000,
????????????????fill:?"forwards"
????????????})
});
直播的世界消息或者彈幕
這是一個我們項目中一個實(shí)際的例子, 直播的彈幕。
我們需要消息先運(yùn)動到屏幕中間,消息最少需要在停留2秒,如果消息過長,消息還需要勻速滾動,之后再滑出屏幕。
滑入暫停,如果消息過長,消息還需要勻速滾動滑出
難點(diǎn)就在于css js讓gif循環(huán)播放,暫停階段,消息滾動的時間并不是確定的,需要計算。這個時候,純CSS3的動畫,難度就有些高了,采用 Web API,天然的和JS親和,那就簡單多了。
先看看效果
.gif
代碼也就簡單的分為三段:滑入,暫停,滑出。
因為其天然支持, 代碼很簡潔,邏輯也很清晰。
async?function?startAnimate()?{
????//?滑入
????const?totalWidth?=?stageWidth?+?DANMU_WITH;
????const?centerX?=?stageWidth?*?0.5?-?DANMU_WITH?*?0.5;
????const?kfsIn?=?{
????????transform:?[`translateX(${totalWidth}px)`,?`translateX(${centerX}px)`]
????}
????await?danmuEl.animate(kfsIn,?{
????????duration:?2000,
????????fill:?'forwards',
????????easing:?'ease-out'
????}).finished;
????//?暫停部分
????const?contentEl?=?danmuEl.querySelector(".danmu-content");
????const?itemWidth?=?contentEl.getBoundingClientRect().width;
????const?gapWidth?=?Math.max(0,?itemWidth?-?DANMU_WITH);
????const?duration?=?Math.max(0,?Math.floor(gapWidth?/?200)?*?1000);
????const?translateX?=?duration?>?0???gapWidth?:?0;
????const?kfsTxt?=?{
????????transform:?[`translateX(0px)`,?`translateX(-${gapWidth}px)`]
????};
????await?contentEl.animate(kfsTxt,?{
????????duration,
????????delay:?2000,
????????fill:?'forwards',
????????easing:?'linear',
????}).finished;
????//?滑出
????const?kfsOut?=?{
????????transform:?[`translateX(${centerX}px)`,?`translateX(-${DANMU_WITH}px)`]
????};
????await?danmuEl.animate(kfsOut,?{
????????duration:?2000,
????????fill:?"forwards",
????????easing:?'ease-in'
????}).finished;
????if?(danmuEl)?{
????????stageEl.removeChild(danmuEl);
????}
????isAnimating?=?false
}
web API 兩個核心的對象 描述動畫屬性 控制播放
描述動畫屬性的集合,調(diào)用及 [2]。然后可以使用[3]構(gòu)造函數(shù)進(jìn)行播放。
其有三種構(gòu)建方式,著重看第二種,參數(shù)后面說。
new (, );
new (, , )
new ()
當(dāng)然我們可以顯示的去創(chuàng)建 , 然后交付給去播放。但是我們通常不需要這么做, 有更加簡單的API, 這就是接后面要說的.[4]。
看一個復(fù)用的例子,new ()基于當(dāng)前復(fù)制,然后多處使用。
const?box1ItemEl?=?document.querySelector(".box1");
const?box2ItemEl?=?document.querySelector(".box2");
const?kyEffect?=?new?KeyframeEffect(null,?{
????transform:?['translateX(0)',?'translateX(200px)']
},
{?duration:?3000,?fill:?'forwards'?})
const?ky1?=?new?KeyframeEffect(kyEffect);
ky1.target?=?box1ItemEl;
const?ky2?=?new?KeyframeEffect(kyEffect);
ky2.target?=?box2ItemEl;
new?Animation(ky1).play();
new?Animation(ky2).play();
kf2.[5]
提供播放控制、動畫節(jié)點(diǎn)或源的時間軸??梢越邮苁褂肹6]構(gòu)造函數(shù)創(chuàng)建的對象作為參數(shù)。
const?box1ItemEl?=?document.querySelector(".box1");
const?kyEffect?=?new?KeyframeEffect(box1ItemEl,?{
????transform:?['translateX(0)',?'translateX(200px)']
},
{?duration:?3000,?fill:?'forwards'?})
const?ani1?=?new?Animation(kyEffect);
ani1.play();
ani1.gif常用的方法 事件監(jiān)聽
監(jiān)聽有兩種形式:
event 方式因其繼承于,所有依舊有兩種形式
animation.onfinish?=?function()?{
??element.remove();
}
animation.addEventListener("finish",?function()?{
??element.remove();
}
形式
animation.finished.then(()?=>
??element.remove()
)
比如一個很有用的場景,所有動畫完成后:
Promise.all(?element.getAnimations().map(ani?=>?ani.finished)
?).then(function()?{???????????
????//?do?something?cool?
??})
常用事件回調(diào)
便捷的.[15]
任何[16]都具備該方法, 其語法:
(, )
其參數(shù)和new (, , )的后兩個參數(shù)基本一樣, 返回的是一個對象。
第一個參數(shù)
有兩種形式,一種是數(shù)組形式,一種是對象形式。
數(shù)組形式
一組對象(關(guān)鍵幀) ,由要迭代的屬性和值組成。
關(guān)鍵幀的偏移可以通過提供一個來指定 ,值必須是在[0.0, 1.0]這個區(qū)間內(nèi),且須升序排列。簡單理解就是進(jìn)度的百分比的小數(shù)值。
element.animate([?{?opacity:?1?},
??????????????????{?opacity:?0.1,?offset:?0.7?},
??????????????????{?opacity:?0?}?],
????????????????2000);
并非所有的關(guān)鍵幀都需要設(shè)置。沒有指定的關(guān)鍵幀將與相鄰的關(guān)鍵幀均勻間隔。
對象形式
一個包含key-value鍵值的對象需要包含動畫的屬性和要循環(huán)變化的值數(shù)組。
element.animate({
??opacity:?[?0,?0.9,?1?],
??offset:?[?0,?0.8?],?//?[?0,?0.8,?1?]?的簡寫
??easing:?[?'ease-in',?'ease-out'?],
},?2000);
第二個參數(shù)
和new (, , )的第三個參數(shù)基本一致,但是多了一個可選屬性,就是id,用來標(biāo)記動畫,也方便 在.[17]結(jié)果中精確的查找。
參數(shù)名含義
delay
延遲動畫開始的毫秒數(shù)。默認(rèn)為0。
動畫運(yùn)動方向
動畫每次迭代完成所需的毫秒數(shù)。默認(rèn)為0
動畫曲線函數(shù),可以自定義
動畫結(jié)束后要延遲的毫秒數(shù)。這主要用于基于另一個動畫的結(jié)束時間對動畫進(jìn)行排序。默認(rèn)為0。
fill
動畫結(jié)束后屬性值的狀態(tài)
描述動畫應(yīng)該在迭代的什么時候開始。0.5表示在第一次迭代中途開始,使用這個值集,一個有兩次迭代的動畫將在第三次迭代中途結(jié)束。默認(rèn)為0.0
動畫應(yīng)該重復(fù)的次數(shù)。默認(rèn)值為1,也可以取一個值 ,使其在元素存在期間重復(fù)。
動畫和其他單獨(dú)的動畫之間組合。這是個高級特性,默認(rèn)是,就是替換提起的動畫。
動畫的屬性值變化如何在每次動畫迭代時累積或相互覆蓋
后續(xù)四個特性相對高級,掌握好了可以玩出花來,本章主要講基本知識,后續(xù)會出高級版本。
更多細(xì)節(jié)可以參見[18]
.[19]
我們通過.或者創(chuàng)建給添加很多動畫,通過這個方法可以獲得所有的實(shí)例。
在需要批量修改參數(shù),或者批量停止動畫的時候,那可是大殺器。
比如批量暫停動畫:
box1ItemEl.getAnimations()
????.forEach(el=>?el.pause())?//?暫停全部動畫
優(yōu)勢相對css動畫更加靈活相對// 動畫,性能更好,代碼更簡潔天然支持,爽爽爽!?。?/p>
你有什么理由拒絕她呢?
對比 CSS 動畫參數(shù)屬性鍵對照表Web
delay
-delay
-
--count
-
--
fill
-fill-mode
參數(shù)設(shè)置值上的區(qū)別參數(shù)只支持毫秒迭代次數(shù)無限使用的是 JS的,不是字符串""默認(rèn)動畫的貝塞爾是,而不是css的ease兼容性
整體還不錯,偏差。
如果不行, 加個墊片web--js[20]。
我們在實(shí)際的桌面項目上已經(jīng)使用,非常靈活, nice!
總結(jié)
web API 和 css動畫,不是誰替換誰。結(jié)合使用,效果更佳。
復(fù)雜的邏輯動畫,因為web API和JS天然的親和力,是更優(yōu)的選擇。
引用
Web API[22]
Using the Web API[23]
CSS vs Web [24]
參考資料[1]
Web API:
[2]
此頁面仍未被本地化, 期待您的翻譯!: **
[3]
:
[4]
.:
[5]
:
[6]
:
[7]
():
[8]
():
[9]
pause():
[10]
play():
[11]
():
[12]
:
[13]
:
[14]
:
[15]
.:
[16]
:
[17]
.:
[18]
:
[19]
.:
[20]
web--js:
[21]
:
[22]
Web API:
[23]
Using the Web API:
[24]
CSS vs Web :
- EOF -