javascript
<template >
<div class="container">
<div class="box1">
<ul>
<!-- <li v-for="(item,index) in lrc" -->
<li v-for="(item,index) in result"
:class="colorHover===index?'lrcHighLight':'lrcDefault'"
:key="index" @mousedown="mousedown(index,item)">
{{ item.words }}
</li>
</ul>
</div>
<div class="box2">
<audio
controls
ref="audio"
@timeupdate="timeUpdate"
@ended="overAudio"
@pause="onPause"
@play="onPlay"
>
<source src="./song/song.mp3" type="audio/mpeg"/>
</audio>
</div>
</div>
</template>
<script>
import { lrc } from './song/index.js';
export default {
name: "test",
data() {
return {
result: [], // 歌词时间对象
audio: this.$refs.audio,
doms: {},
colorHover: 0
};
},
created() {
// 解析歌词并渲染
this.parseLrc();
},
computed: {
// audioCurrentTime(){
// var _this = this;
// this.$nextTick(() => {
// alert(_this.$refs.audio.currentTime);
// // return document.querySelector('audio').currentTime;
// return _this.$refs.audio.currentTime;
// })
// }
},
watch: {
// audioCurrentTime(oldTime, newTime) {
// console.log(1);
// this.findIndex();
// }
},
mounted() {
// this.addEventListeners();
// this.$refs.audio.addEventListener('timeupdate', this.setOffset());
this.doms = {
audio: this.$refs.audio,
ul: this.$el.querySelector(".container ul"),
container: this.$el.querySelector('.container'),
}
// 播放器默认音量,最大音量1
this.$refs.audio.volume = 0.25;
},
methods: {
// addEventListeners: function () {
// this.$refs.audio.addEventListener('timeupdate', this.setOffset());
// },
// addEventListeners: function () {
// const audio = this.$refs.audio;
// self.$refs.audio.addEventListener('timeupdate', audio.currentTime)
// // self.$refs.player.addEventListener('canplay', audio.durationTime)
// },
/** 解析歌词字符串
* 得到一个歌词对象的数组
* 每句歌词对象:
* {time: 开始时间, words: 歌词}
*/
parseLrc(){
var lines = lrc.split("\n");
// 存放所有时间/歌词数组
this.result = [];
lines.forEach(item => {
var parts = item.split("]");
var timeStr = parts[0].substring(1);
// this.parseTime(timeStr);
var obj = {
time: this.parseTime(timeStr),
words: parts[1]
}
this.result.push(obj);
})
// this.createLrcElement();
return this.result;
},
// 原生js添加歌词
createLrcElement(){
// 文档片段
var frag = document.createDocumentFragment();
for(var i = 0; i<this.result.length; i++){
var li = this.$el.createElement("li");
li.textContent = this.result[i].words;
frag.append(li);
}
this.doms.ul.appendChild(frag);
},
/**
* 将一个时间字符串解析数字(秒)
* @param {string} timeStr 事件字符串
* @return
*/
parseTime(timeStr){
var parts =timeStr.split(":");
return +parseInt(parts[0]) * 60 + parseInt(parts[1]);
},
/**
* 计算出播放器当前播放时间应该高亮哪句歌词的下标
*
*/
findIndex() {
var lrcTime = this.result;
// DOM上绑定的src属性无法立即更新
// var curTime = document.querySelector('audio').currentTime;
var curTime = this.$refs.audio.currentTime
for(var i = 0; i < lrcTime.length; i++){
// console.log('播放器当前时间', curTime)
// console.log('歌词时间', lrcTime[i].time)
if(curTime < lrcTime[i].time) {
// console.log(lrcTime[i].words);
return i - 1;
}
}
// 如果遍历完没有歌词,说明播放到最后一句了
return lrcTime.length - 1;
},
test(){
// 容器高度
var containerHeight = this.doms.container.clientHeight;
// 每个 li 的高度
var liHeight = this.doms.ul.children[0].clientHeight;
},
/**
* 设置 Ul 的偏移量
*/
setOffset(){
// 容器高度
// var containerHeight = this.doms.container.clientHeight;
// // 每个 li 的高度
// var liHeight = this.doms.ul.children[0].clientHeight;
var index = this.findIndex();
this.colorHover = index;
// alert(index)
// var offset = liHeight * index + liHeight / 2 - containerHeight / 2;
// if(offset < 0){
// offset = 0;
// }
// if(offset > maxOffset){
// offset = maxOffset;
// }
// this.doms.ul.style.transform = `translateY(-${offset}px)`;
// // 去掉之前的 active 的样式
// var li = this.doms.ul.querySelector('.active');
// if(li){
// li.classList.remove('active');
// }
// li = this.doms.ul.children[index];
// if(li){
// li.classList.add('active');
// }
},
// 监听播放器时间
timeUpdate() {
this.setOffset();
},
// 当音频播放
onPlay () {
console.log('开始播放声音');
},
// 当音频暂停
onPause () {
console.log('暂停播放声音');
},
//播放完毕执行
overAudio(){
console.log('播放声音完毕');
},
mousedown(index, item){
console.log(this.$refs.audio);
this.$refs.audio.currentTime = item.time;
this.timeUpdate();
},
}
};
</script>
<style lang="scss" scoped>
.lrcDefault{
color:black;
}
.lrcHighLight{
// transform: scale(1.5);
// transition: 1s ease-in;
color:#00a0e9;
}
.box1{
display: flex;
justify-content: center;
height: 90%;
}
.box2{
display: flex;
justify-content: center;
height: 10%;
bottom: -12px;
background-color: #000;
box-shadow: 0 -10px 20px #403f3f;
}
ul{
list-style-type: none;
height: 90%;
overflow-y: scroll;
scrollbar-color: dark;
/** 隐藏滚动条,但是元素还是可以滚动 */
scrollbar-width: none;
li{
height: 30px;
line-height: 30px;
font-size: 16px;
cursor:pointer;
}
}
.container{
height: 80vh;
background: #708090;
}
</style>
java
var lrc = `[0:00:00]小手拉大手-许梦
[0:06:00]词-陈大毛
[0:13:00]曲-过儿
[0:20:14]编曲-狗蛋
[0:27:08]还记得那场音乐会的烟火
[0:30:02]还记得那个凉凉的深秋
[0:34:13]还记得人潮把你推向了我
[0:38:13]游乐园拥挤的正是时候
[0:42:26]一个夜晚坚持不睡的等候
[0:45:01]一起泡温泉奢侈的享受
[0:49:01]有一次日记里愚蠢的困惑
[0:53:01]因为你的微笑幻化成风
[0:56:01]你大大的勇敢保护着我
[01:02:01]我小小的关怀喋喋不休
[01:04:01]感谢我们一起走了那么久
[01:07:01]又再一次回到凉凉深秋
[01:11:01]给我你的手
[01:13:34]像温柔野兽
[01:15:53]把自由交给草原的辽阔
[01:19:06]我们小手拉大手
[01:21:35]一起郊游
[01:23:11]今天别想太多
`;
// 注意"歌词行"别留空格
export {
lrc,
}
1.歌曲需下载
2.点击歌词播放,如果初始化时暂停状态,需手动点击播放(累,没去看aduio方法)
3.歌词时间不准确,自己手动输入的时间,只影响点击歌词播放功能一点点
4.本意是想用原生写(注释部分),但vue框架始终报错document未定义,未果。
5.写得有点乱,望海涵!