播放标签
<audio id="songPlayAudio" :src="playUrl" ref="songPlayAudioRef" controls style="display: none;"
@ended="onended"></audio>
歌词滚动区,需要在解析歌词后,根据播放时间高亮对应歌词并滚动
< !--歌词滚动区 -->
<div class="lyric-box">
<div class="detail">
<div class="wrapper">
<ul class="lyric" v-show="isShowMusicList" ref="lyricRef">
<li v-for="(item, index) of ParsedLyricsArray" :key="index">{{ item.c }}</li>
</ul>
</div>
</div>
</div >
对应歌曲滚动区的样式
.lyric-box {
height: 40vh;
overflow: hidden;
position: relative;
.not-data {
margin-top: 1.875rem;
font-size: 16px;
color: #cdcdc6;
}
.detail {
position: absolute;
top: 0;
bottom: 2.6rem;
left: 0;
right: 0;
color: rgba(255, 255, 255, 0.65);
.lineHigh {
color: #FFD700;
}
.wrapper {
overflow: hidden;
position: absolute;
top: 2rem;
right: 0;
left: 0;
height: 545px;
// background-color: red;
ul {
line-height: 32px;
width: 100%;
padding-bottom: 1rem;
display: flex;
flex-direction: column;
flex-wrap: wrap;
li {
font-size: 16px;
transition-duration: 1200ms;
}
}
}
}
}
定义的变量
// 歌词节点
const lyricRef = ref(null);
const lineNo = ref(0);
const Cpos = ref(7);
const offset = ref(-32);
后台返的歌词数组 本来后端返回的是一个歌词URL地址的,点击地址链接可以直接拿到lrc文件。但是前端需要再请求一次歌词地址,结果产生了跨域问题。所以最后,还是请后端把数据处理好返回,这样子就省事很多了,方便后续直接做歌词的解析。
// 后台返的歌词数组
lyricsArray: `
[ti:不一样了]
[ar:许茹芸]
[al:]
[by:]
[offset:0]
[00:00.01]不一样了 - 许茹芸
[00:01.24]词:天天
[00:01.95]曲:马怡静
[00:02.81]
[00:19.21]打开窗帘的一刹那
[00:22.73]
[00:23.29]看窗户洒进来的阳光
[00:27.02]
[00:27.85]那天早晨的心情也完全不一样
[00:34.59]
[00:36.44]光线像双眼般透亮
[00:39.76]
[00:40.50]脸上也悄悄泛起红光
[00:44.02]
[00:44.76]莫名心动
[00:46.52]因为你一一涌上
[00:52.08]
[00:53.33]在心的深处有一双翅膀
`,
对歌词进行解析操作: 此处需要注意:后台返回的歌词数组格式不一定全部都是正确的,有的可能会缺失歌词时间之类的,所以可能会导致后面网页显示出现问题。所以,需要考虑做判断,在歌词返回格式不正确的时候,可以按无歌词状态来表示或者啥的......
// lyricsArray是后端获取到的lrc格式的歌词文件
if (singInfo.lyricsContent.length == 0) return;
let lrcs = singInfo.lyricsContent.split('\n');//用回车拆分成数组
// console.log(`歌词数据=======`, lrcs)
for (let i in lrcs) {//遍历歌词数组
lrcs[i] = lrcs[i].replace(/(^\s*)|(\s*$)/g, ""); //去除前后空格
// 歌词行数的播放时间
let t = lrcs[i].substring(lrcs[i].indexOf("[") + 1, lrcs[i].indexOf("]"));//取[]间的内容
let s = t.split(":");//分离:前后文字
if (!isNaN(parseInt(s[0]))) { //是数值
let arr = lrcs[i].match(/\[(\d+:.+?)\]/g);//提取时间字段,可能有多个
let start = 0;
for (let k in arr) {
start += arr[k].length; //计算歌词位置
}
let content = lrcs[i].substring(start);//获取歌词内容
for (let k in arr) {
let t = arr[k].substring(1, arr[k].length - 1);//取[]间的内容
let s = t.split(":");//分离:前后文字
if (!content) {
break;
}
ParsedLyricsArray.value.push({//对象{t:时间,c:歌词}加入ms数组
t: (parseFloat(s[0]) * 60 + parseFloat(s[1])).toFixed(3),
c: content
});
}
}
}
解析好歌词后再进行歌词对应时间滚动
// 组件挂载时调用
onMounted(() => {
// 监听歌词进度与播放高亮一致
songPlayAudioRef.value.addEventListener('timeupdate', () => {
if (lineNo.value == ParsedLyricsArray.value.length)
return;
// songPlayAudioRef.value.currentTime播放器时间
if (parseFloat(ParsedLyricsArray.value[lineNo.value].t) <= songPlayAudioRef.value.currentTime) {
lineHigh();//高亮当前行
lineNo.value++;
}
})
})
//结束执行
const onended = () => {
console.log('onended--结束执行-');
goback(); //回滚歌词
}
// 重新播放是歌词重置事件
const goback = () => {
document.querySelector(".lineHigh").removeAttribute("class");
lyricRef.value.style.transform = "translateY(0)";
lineNo.value = 0; //lineNo清零,重新播放
}
// 高亮歌词滚动事件
const lineHigh = () => {
const list = lyricRef.value.getElementsByTagName("li");
if (lineNo.value > 0) {
list[lineNo.value - 1].removeAttribute("class");//去掉上一行的高亮样式
}
list[lineNo.value].className = "lineHigh";//高亮显示当前行
//文字滚动
if (lineNo.value > Cpos.value) {
lyricRef.value.style.transform = "translateY(" + (lineNo.value - Cpos.value) * offset.value + "px)"; //整体向上滚动一行高
}
}
特别说明:每一篇文章,都是针对自己做过的项目而记下的笔记;笔记的内容也是参考网上的资料,我就是个搬运工,整合成了自己的笔记。如需要参考的,请根据自己实际项目需求参考。