我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛
效果展示
码上掘金地址
实现思路分析
- 上边是简单的audio元素, 关键事件
@timeupdate, 约每秒触发一次
<audio @timeupdate="change_video"></audio>
- 下边就是vue循环的一个列表
<div class="container">
<div class="list">
<div v-for="(item,index) in list" class="li">
{{item.words}}
</div>
</div>
</div>
- 可以从.lrc文件中获取
const lrc = `[00:00:00] 小白兔白又白 - 甜筒星球
[00:03:00] 词:佚名
[00:04:00] 曲:佚名
[00:07:00] 小白兔
[00:08:00] 白又白
[00:09:00] 两只耳朵竖起来
[00:11:00] 爱吃萝卜爱吃菜
[00:14:00] 蹦蹦跳跳 真可爱
[00:26:00] 小白兔
[00:27:00] 白又白
[00:28:00] 两只耳朵竖起来
[00:31:00] 爱吃萝卜爱吃菜
[00:33:00] 蹦蹦跳跳 真可爱
[00:45:00] 小白兔
[00:46:00] 白又白
[00:47:00] 两只耳朵竖起来
[00:50:00] 爱吃萝卜爱吃菜
[00:52:00] 蹦蹦跳跳 真可爱`
- 处理成可用的数组格式,时间格式还原为秒数
[
{
time: 14
words: "蹦蹦跳跳 真可爱"
}
// ...
]
lrc.split('\n').map(i=>{
let s = i.split(']')
let times = s[0].substring(1).split(':')
return {
time: times[0] * 60 + +times[1],
words: s[1]
}
})
- 记录当前播放进度
change_video(val){
console.log(this.$refs.my_audio.currentTime)
let index = this.list.findIndex(i=>i.time >= this.$refs.my_audio.currentTime)
this.index_now = index > 1 ? index - 1 : 0
}
- 显示播放当前行高亮
:class="{active: index == index_now}" - 重点是计算元素
.list的偏移,偏移用cssstyle="transform: translateY(-220px)", 改变值即可实现偏移
<div class="container">
<div class="list" :style="{transform: computed_y}">
<div v-for="(item,index) in list" class="li" :class="{active: index == index_now}">
{{item.words}}
</div>
</div>
</div>
computed: {
computed_y(){
let top = this.index_now * 30 - 250
if(top < 0){
top = 0
}
return `translateY(-${top}px)`
}
}
- 还有一个过渡属性
transition: 0.3
transition: 0.3s;
浏览器兼容性
QA: 为什么位移优先选择使用transform, 而不是margin-top?
改变transform、opacity这种,只需要在GPU内部基于绘制好的纹理进行变换或混合,不会引起重排和重绘。