时间:2023-02-03 07:39:04 | 栏目:JavaScript代码 | 点击:次
相信大多前端同学都自己写过音频、视频播放器,实现并不复杂。最近在小程序里,做了一个类似微博刷视频的需求。其中有一部分功能需要实现自定义进度条,在做完第一版之后发现进度条不顺滑,而后想查查网上看有没有什么好的方案,但最终没找到合适的。于是想看看微信小程序里的“微博”进度条如何,结果也是很生硬的动画,下面放了一个GIF,大家也可以自己搜索微信小程序的微博,找个视频看看效果。
最终决定还是优化一下这个问题,先来捋一捋我们现有常规方案。
现有的方案是依赖事件获取当前播放时间,而这个事件大概在100~350毫秒触发一次,下面是我记录的小程序的事件对象队列。
[ {"detail":{"currentTime":0.10509,"duration":5.83}}, {"detail":{"currentTime":0.364527,"duration":5.83}}, {"detail":{"currentTime":0.613648,"duration":5.83}}, ]
目前的问题在于,每次获取到事件,就会更新进度条,没有过度动画效果,非常的生硬,下面是一个5s总时长的进度条变化过程:
核心代码:
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的动画属性来做优化,想要灵活的控制,我选择使用 transition。transition可以定义动画执行时长,当我们改变width时,transition就会在规定时间内用动画的方式改变进度条宽度。首先动画执行时长一定要固定,并且在上一个执行时长结束之前最好不要再对width做改动,否则会导致冲突,动画会变得很奇怪。
听起来有点不好理解,我们画个图:
核心代码:
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+'%' } //当前视频进度第一次更新 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版本看起来和普通版差不多?把另一个60s挡住,来回对比,会发现还是有些区别。
解释起来还是有点费劲,还是没看明白?直接去看github仓库代码,代码可直接运行:https://github.com/zimv/smooth-progress
此方案在部分场景下会有短暂延迟,比如暂停、拖动等,个人总体觉得利大于弊。