梦想做个厨子,结果成了码农
听久了云村音乐,加上自己是个前端,于是想尝试造个轮子。
歌词同步
实现难点
歌词是这般的
[00:18.640]这街上太拥挤
[00:20.820]太多人有秘密
于是你要基于前面的时间,在与当前播放的时间去做对比,选出下一句歌词。
仔细想想好像也就那回事。
实现方式
- 基于 timeupdate 的时间去判断
- 基于时间戳,然后利用 setTimeout 标准延迟(delay多少就是多少)
具体实现
第一种
audio.addEventListener('timeupdate',function(){
let liveTime = parseFloat((audio.currentTime).toFixed(2))// + 0.2;
let _next = timeArr.findIndex((item, idx) => {
if(liveTime >= (item - offset) && liveTime < (timeArr[idx + 1] - offset)){
return true
}
// 开局歌词不是从零开始 , 或者结尾的时候
if(!timeArr[idx + 1] || liveTime < item){
return true
}
return idx === timeArr.length
})
if(_next !== -1) {
let ele = $('.Lyrics').children(`p:eq(${_next})`)
if(!curIndex || (curIndex && ele.html() !== curIndex.html())){
lyrSroll(ele)
}
}
})
当currentTime更新时会触发timeupdate事件,简单理解为在播放的时候,事件就会一直被触发。
这个事件的触发频率由系统决定,但是会保证每秒触发4-66次(前提是每次事件处理不会超过250ms)。
换句话说,就是一秒内执行的次数,不固定。引起的后果就是,有的歌词快点出来,有的慢点。
所以爆肝了,over。
第二种
function _playRest() {
let line = timeArr[curNum]
let delay = line - (Date.now() - startStamp)
timer = setTimeout(() => {
lyrSroll($('.Lyrics').children(`p:eq(${curNum++})`))
if (curNum < timeArr.length && !audio.paused) {
_playRest()
}
}, delay)
}
这种是基于 取歌词时的时间戳 - 开始播放的时间戳 = 歌曲已经开始了的时间。然后就可以很帅气的使用 歌词的时间 - 歌曲已经开始的时间,即这个歌词延迟多久出现。
开发后,还是这个完美一些。
最后附上一个大概算是最终版吧,传送门
参考资料
1.https://developer.mozilla.org/zh-CN/docs/Web/Events/timeupdate
2.https://github.com/ustbhuangyi/lyric-parser
打破0回复惨案!