JS實(shí)現(xiàn)進(jìn)度條順滑版詳細(xì)方案
進(jìn)度條不順滑
相信大多前端同學(xué)都自己寫過音頻、視頻播放器,實(shí)現(xiàn)并不復(fù)雜。最近在小程序里,做了一個(gè)類似微博刷視頻的需求。其中有一部分功能需要實(shí)現(xiàn)自定義進(jìn)度條,在做完第一版之后發(fā)現(xiàn)進(jìn)度條不順滑,而后想查查網(wǎng)上看有沒有什么好的方案,但最終沒找到合適的。于是想看看微信小程序里的“微博”進(jìn)度條如何,結(jié)果也是很生硬的動畫,下面放了一個(gè)GIF,大家也可以自己搜索微信小程序的微博,找個(gè)視頻看看效果。

常規(guī)方案
最終決定還是優(yōu)化一下這個(gè)問題,先來捋一捋我們現(xiàn)有常規(guī)方案。
- 監(jiān)聽TimeUpdate事件
- 獲取到當(dāng)前播放時(shí)間,通過總時(shí)間計(jì)算進(jìn)度百分比(currentTime / duration * 100)
- 進(jìn)度條width屬性設(shè)置進(jìn)度百分比
現(xiàn)有的方案是依賴事件獲取當(dāng)前播放時(shí)間,而這個(gè)事件大概在100~350毫秒觸發(fā)一次,下面是我記錄的小程序的事件對象隊(duì)列。
[
{"detail":{"currentTime":0.10509,"duration":5.83}},
{"detail":{"currentTime":0.364527,"duration":5.83}},
{"detail":{"currentTime":0.613648,"duration":5.83}},
]
目前的問題在于,每次獲取到事件,就會更新進(jìn)度條,沒有過度動畫效果,非常的生硬,下面是一個(gè)5s總時(shí)長的進(jìn)度條變化過程:

核心代碼:
const onProgress = (e, $dom) => {
const updateFunc = (percent) => {
$dom.style.width = percent+'%'
}
let percent = ((e.detail.currentTime / e.detail.duration) * 100).toFixed(1)
updateFunc(percent)
}
transition
我們能很快想到用CSS的動畫屬性來做優(yōu)化,想要靈活的控制,我選擇使用 transition。transition可以定義動畫執(zhí)行時(shí)長,當(dāng)我們改變width時(shí),transition就會在規(guī)定時(shí)間內(nèi)用動畫的方式改變進(jìn)度條寬度。首先動畫執(zhí)行時(shí)長一定要固定,并且在上一個(gè)執(zhí)行時(shí)長結(jié)束之前最好不要再對width做改動,否則會導(dǎo)致沖突,動畫會變得很奇怪。
- 選擇一個(gè)合理的transition執(zhí)行時(shí)間:0.5s
- 根據(jù)當(dāng)前總時(shí)長,求出0.5s在進(jìn)度條中所屬百分比(100/duration/2)
- 第一次TimeUpdate事件,就執(zhí)行width改變,把進(jìn)度條設(shè)置到0.5s的位置:width = 100/duration/2
- 非第一次TimeUpdate事件,每當(dāng)currentTime超過上一次進(jìn)度條位置,就更新當(dāng)前進(jìn)度條百分比
聽起來有點(diǎn)不好理解,我們畫個(gè)圖:

- 當(dāng)?shù)谝淮斡|發(fā)TimeUpdate事件,0.1336秒的時(shí)候(當(dāng)然這個(gè)值隨機(jī)的,可能是0.1~0.3之間),我們就設(shè)置width到0.5s的位置,這樣進(jìn)度條就和視頻同步在運(yùn)動,和真實(shí)的進(jìn)度相差微弱的0.1秒。在動畫執(zhí)行的0.5s之間,UpdateTime也會有多次觸發(fā),
- 當(dāng)某次UpdateTime的currentTime(0.7123s,這個(gè)值也是隨機(jī)的)值大于上次執(zhí)行的0.5s時(shí),這個(gè)時(shí)候進(jìn)度條的位置大概也在0.5s周圍,我們再次觸發(fā)下一個(gè)0.5s動畫,也就是把width設(shè)置為1s的進(jìn)度條位置
- 而后下個(gè)迭代currentTime>1s,width設(shè)置為1.5s,這樣循環(huán)下去。
核心代碼:
const playControl = {
percent: 0,
time: 0,
duration: 0,
first: true
}
const onProgress = (e, $dom) => {
const updateFunc = (percent) => {
playControl.percent = percent
playControl.time = e.detail.currentTime
$dom.style.width = percent+'%'
}
//當(dāng)前視頻進(jìn)度第一次更新
if (playControl.first) {
playControl.duration = e.detail.duration
playControl.first = false
updateFunc(100 / e.detail.duration / 2)
} else {
let percent = ((e.detail.currentTime / e.detail.duration) * 100).toFixed(1)
if (percent - playControl.percent > 0 || e.detail.currentTime >= e.detail.duration) {
updateFunc(percent)
}
}
}
最終效果對比(PS:gif圖效果有折損)

60s版本看起來和普通版差不多?把另一個(gè)60s擋住,來回對比,會發(fā)現(xiàn)還是有些區(qū)別。
解釋起來還是有點(diǎn)費(fèi)勁,還是沒看明白?直接去看github倉庫代碼,代碼可直接運(yùn)行:https://github.com/zimv/smooth-progress
此方案在部分場景下會有短暫延遲,比如暫停、拖動等,個(gè)人總體覺得利大于弊。
到此這篇關(guān)于JS實(shí)現(xiàn)進(jìn)度條順滑版詳細(xì)方案的文章就介紹到這了,更多相關(guān)JS進(jìn)度條順滑版 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
countUp.js實(shí)現(xiàn)數(shù)字滾動效果
這篇文章主要為大家詳細(xì)介紹了countUp.js實(shí)現(xiàn)數(shù)字滾動效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
CocosCreator實(shí)現(xiàn)技能冷卻效果
這篇文章主要介紹了CocosCreator實(shí)現(xiàn)技能冷卻效果,同學(xué)們可以跟著教程,親手試一下,代碼都是可以復(fù)用的2021-04-04
Javascript 浮點(diǎn)運(yùn)算的問題分析與解決方法
JavaScript 只有一種數(shù)字類型 Number ,而且在Javascript中所有的數(shù)字都是以IEEE-754標(biāo)準(zhǔn)格式表示的。 浮點(diǎn)數(shù)的精度問題不是JavaScript特有的,因?yàn)橛行┬?shù)以二進(jìn)制表示位數(shù)是無窮的2013-08-08
JavaScript實(shí)現(xiàn)樓梯滾動特效(jQuery實(shí)現(xiàn))
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)樓梯滾動特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
ES6 Array常用擴(kuò)展的應(yīng)用實(shí)例分析
這篇文章主要介紹了ES6 Array常用擴(kuò)展的應(yīng)用,結(jié)合實(shí)例形式分析各種常見擴(kuò)展方法針對Array數(shù)組的轉(zhuǎn)換、遍歷、查找、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2019-06-06
微信小程序之側(cè)邊欄滑動實(shí)現(xiàn)過程解析(附完整源碼)
這篇文章主要介紹了微信小程序之側(cè)邊欄滑動實(shí)現(xiàn)過程解析(附完整源碼),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
禁用頁面部分JavaScript方法的具體實(shí)現(xiàn)
方法重寫,重寫要禁用的方法,并讓它什么也不做,結(jié)果證明真的可行,但并不知道是不是一個(gè)科學(xué)的方法,我拿出來與大家共同討論一下2013-07-07

