js中关于音频歌词随歌曲播放自动滚动

在这里插入图片描述

基本布局

  <div class="musicBox">
   <ul id="showLyric">
   </ul>
   <p class="musicFoot">
    <audio src="music/于此与彼.mp3" controls="controls" autoplay="autoplay"></audio>
    <br/>
   </p>
  </div>

样式

   * {
    padding: 0;
    margin: 0;
   }
   html,body,div,p,ul {
    margin: 0;
    padding: 0;
   }
   html,body {
    background-color: rgba(110, 170, 150, 0.4);
    height: 100%;
    width: 100%;
   }
   .musicBox {
    height: 100%;
   }
   ul,li {
    list-style: none;
   }
   ul{
    height:80%;
    background-color: aqua;
    overflow-y: hidden;
   }
   li {
    text-align: center;
    font-size: 13px;
    height: 20px;
    line-height: 20px;   
   }
   audio{
    height: 30px;
    width: 115%;
    margin-left: -5%;
    margin-top: 12%;
   }
   .musicFoot {
    position: fixed;
    bottom: 0;
    height: 20%;
    width: 100%;
    background-color: mediumpurple;
   }
   button{
    height: 30px;
    width: 25%;
    margin-left: 20px;
   }
   .lineheight{
    color: brown;
    font-size: 15px;
    background-color: antiquewhite;
   }

歌词

[ti:]
[ar:]
[al:]
[by:]
[offset:0]
[00:02.01]与彼于此 - 庞琪祥
[00:04.03]词:张鑫
[00:06.05]曲:张鑫
[00:08.06]编曲:杨朝焰/黄汇雯
[00:10.08]制作人:杨朝焰
[00:13.00]和声:Isabell潘沁珈
[00:15.01]吉他:王保为
[00:17.03]录音:王一名
[00:19.05]混音:王楷尧
[00:21.07]母带:王楷尧
[00:23.08]监制:赵晨
[00:26.00]商务统筹:丁聪
[00:28.02]制作统筹:陈嘉琪
[00:30.03]Op:万有YIN力
[00:32.05]发行公司:万有YIN力
[00:34.07]游来游去忽远忽近
[00:37.07]予取予求半信半疑
[00:40.04]莫名不安和恐惧
[00:46.00]绘声绘色毕恭毕敬
[00:48.07]百依百顺不离不弃
[00:51.04]尝试用面具肯定
[00:57.07]眺望你眼中迷离的风景
[01:03.01]蓝色里透着淡定
[01:08.05]嘴里的愿意 还有都可以
[01:13.01]如此随心所欲游刃有余
[01:21.02]我们还该不该相信彼此
[01:26.09]保留最后一份 
[01:29.06]当初最真挚的样子
[01:34.06]初遇时的相似
[01:38.00]如今是分道扬镳的关键词
[01:43.02]我们还要不要拥抱彼此
[01:48.09]用曾经最熟悉的 
[01:52.03]而现在不愿的方式
[01:57.01]努力放逐灵魂 
[02:01.00]任回忆放肆
[02:05.04]让抚平了的心跳 
[02:09.06]再循环一次
[02:29.03]眺望你眼中迷离的风景
[02:34.08]蓝色里透着淡定
[02:37.02]嘴里的愿意 还有都可以
[02:44.07]如此随心所欲游刃有余
[02:49.04]我们还该不该相信彼此
[02:54.09]保留最后一份 
[02:57.06]当初最真挚的样子
[03:02.08]初遇时的相似
[03:06.02]如今是分道扬镳的关键词
[03:11.03]我们还要不要拥抱彼此
[03:16.07]用曾经最熟悉的 
[03:20.04]而现在不愿的方式
[03:24.06]努力放逐灵魂 任回忆放肆
[03:32.09]让抚平了的心跳 再循环一次
[03:49.03]我们还该不该相信彼此
[03:54.07]保留最后一份 
[03:57.04]当初最真挚的样子
[04:02.03]初遇时的相似
[04:05.08]如今是分道扬镳的关键词
[04:10.07]我们还要不要拥抱彼此
[04:16.00]用曾经最熟悉的 
[04:19.04]而现在不愿的方式
[04:23.07]努力放逐灵魂 任回忆放肆
[04:31.07]让抚平了的心跳 再循环一次

处理歌词,得到每行歌词以及相应时间

  /* 步骤1:
   显示歌词在歌词容器中
        */ 
  // 处理歌词:将字符串转化为数组
  let part=lyric.split('\n')
  // console.log(part)
  for(let index=0;index<part.length;index++){
   // 将数组内的 值处理成:时间+歌词
   part[index]=getObj(part[index])
  }
  console.log(part)  
  // 处理每行歌词
  function getObj(partContent){
   // 将每行切分成:时间+歌词
   let twoParts=partContent.split(']')
   // 获取时间
   let time=twoParts[0].substr(1)
   // 将时间切分成:分+秒
   let timeParts=time.split(':')
   // console.log(timeParts)
   let timeSeconds=timeParts[1]
   let second=Number(timeSeconds)
   let timeMinutes=timeParts[0]
   let minutes=Number(timeMinutes)
   // 保留两位小数
   let seconds=(minutes * 60 +second).toFixed(2)
   let words=twoParts[1]
   return{
    seconds,
    words
   }
  }

将歌词显示在页面上

  let part=lyric.split('\n')
  // console.log(part)
  let liStr=''
  for(let index=0;index<part.length;index++){
   // 将数组内的 值处理成:时间+歌词
   part[index]=getObj(part[index])
   liStr+='<li>'+part[index]['words']+'</li>'
  }
  oul.innerHTML=liStr

歌词高亮以及滚动

在这里插入图片描述

查看歌词容器相关属性值

  console.log('歌词容器的可视高度:'+oul.clientHeight)
  console.log('歌词容器的实际高度:'+oul.scrollHeight)
  console.log('歌词距离容器顶部的偏移:'+lis[12].offsetTop)
  console.log('歌词滚出可视区域的距离:'+oul.scrollTop)
  // 歌词滚动效果
  function heightLyric(linenum){
   // 1、歌词高亮
   // linenum:歌词行号
   let ul=document.getElementById('showLyric')
   if(linenum>0){
    // 当前播放的前一行取消高亮显示,移除相关类
    lis[linenum-1].removeAttribute("class")
   }
   // 歌词当前播放行
   let nowline=lis[linenum]
   nowline.setAttribute("class","lineheight")
   // 2、歌词滚动
   let _scrollTop=0;//歌词滚动出去的距离
   ul.scrollTop=0//初始,歌词滚出容器的距离为0
   let coefficient=0.5
   // 当歌词位于可视区域上面,则不滚动
   //歌词可视区域高度的一半>当前歌词距离容器顶部偏移
   if(ul.clientHeight*coefficient>nowline.offsetTop){
    _scrollTop=0
    //当前行距离顶部频移 >(歌词容器实际距离-可视容器距离的一半
   }else if(nowline.offsetTop>(ul.scrollHeight-ul.clientHeight*(1-coefficient))){
   // 当最后一行歌词出现在可视区域,则不再向上滚动
    _scrollTop=ul.scrollHeight-ul.clientHeight
   }else{
   // 否则,滚动
    _scrollTop=nowline.offsetTop-ul.clientHeight*coefficient
   }
   /* 当前行距离顶部的偏移-滚动的距离>歌词可视区的一半
   说明:当前行在可视区域一半的位置以下,需要向上滚动 */
   if((nowline.offsetTop-ul.scrollTop)>ul.clientHeight*coefficient){
    ul.scrollTop+=Math.ceil(nowline.offsetTop-ul.scrollTop-ul.clientHeight*coefficient)
   }else if((nowline.offsetTop-ul.scrollTop)<ul.clientHeight*coefficient && _scrollTop!=0){
    //当前歌词在可视区域一半以上
    ul.scrollTop -=Math.ceil(ul.clientHeight*coefficient-(nowline.offsetTop-ul.scrollTop))
   }else if(_scrollTop==0){
    ul.scrollTop=0
   }else{
    ul.scrollTop+=lis[linenum].clientHeight
   }
  }

获取歌词中存在歌词的首行的索引

  let i=0
  let linenum=0
  do{
   i++
  }while(lis[i].innerHTML =='undefined'|| lis[i].innerHTML==''){
   linenum=i
  }
  // console.log('linenum'+linenum)

音频监听,歌词滚动

音频监听事件

audio.addEventListener('timeupdate',lyricScroll)
  audio.addEventListener('timeupdate',function lyricScroll(){   
   if(linenum==part.length-1 && audio.currentTime.toFixed(2) >= parseFloat(part[linenum]['seconds'])){
    heightLyric(lineno)
   }
   if(audio.currentTime.toFixed(2) >= parseFloat(part[linenum]['seconds']) && audio.currentTime.toFixed(2)<=parseFloat(part[linenum+1]['seconds'])){
    heightLyric(linenum)
    linenum++
   }
  })

猜你喜欢

转载自blog.csdn.net/weixin_40119412/article/details/107932363