网易云歌词居中滚动、点击/滑动进度条对应滚动、当前播放歌词高亮

当前播放歌词高亮:
	根据当前播放时间,和歌词时间对比,获得当前歌词行数索引

正常居中滚动、点击/滑动进度条对应滚动:
	(1)因为这几种方式都是改变当前播放时间,所以只需要根据当前播放时间操作即可
	
	(2)根据当前播放时间,得到当前歌词行数,因为设置歌词和空白高度都是一定的,所以可以根据行数确定居中位置
	
	(3)当行数小于指定行或大于指定行时,滚动顶部/底部,在其中居中
		居中方式:将滚动条移动=当前行到顶部的距离(-90是因为父元素到滑动区域的距离有90)-行高度*在多少(n)行就可居中

效果图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码示例:

<template>
   <div class='s'>
    <div class='scale' @click="scale">
         <span><a-icon type="fullscreen-exit" /></span>
    </div>
     <div class='b-i'>
         <img height="100px" :src="imgUrl" alt="">
     </div> 

     <div class='c-c' :class={done:!isplay,on:isplay}>
         <img :src="imgUrl" alt="">
     </div> 

     <div class='c-l'>
         <div class='c-i'>
            <p>海阔天空</p>
            <div>歌手: beyond</div>
         </div>
         <div class='c-lyr' ref='scroll' >
             <ul ref='ul'>
                 <!-- :class='{hight:high(item.time,lyrs[index+1].time,time)}' -->
                 <!-- :class='{hight:time>item.time&&time<lyrs[index+1].time}' -->
                     <!-- high(index,lyrs,time) -->
                 <li v-for="(item,index) in lyrs" :key='index'  :class='{hight:index==highlightLine}'>
                     {{item.lyr}}
                 </li>
             </ul>
         </div>
     </div>

   </div>
</template>

<script>
import axios from 'axios';

export default {
  name:'song',
  props:['isplay','time'],
  data(){
    return{
      imgUrl:'',
      lyric:'',
      lyrs:[],
      lis:[],
      tops:[],
      highlightLine:0
    }
  },
  methods:{
      scale()
      {
          this.$emit('mini')
      },
      //正则处理歌词
      regRex(str)
      {

        // var reg= /(ru)n(oob)/i
        //获取歌词贡献者
          let regUser=/\[(.*)\]\n/igm

          let user=regUser.exec(str);
          str=str.substring(user[0].length,str.length);
        
        //匹配歌词
          let reg=/\[(.*)\](.*)\n/igm
          let res;
          while(res=reg.exec(str))
          {

            this.lyrs.push({time:this._timeForm(res[1]),lyr:res[2]});
          }
          console.log(this.lyrs);
      },
      //将字符串xx:xx的时间格式处理成秒
      _timeForm(time)
      {
          let index=time.indexOf(':');
          let min=time.substring(0,index);
          let seconds=time.substring(index+1,time.length);
          return min*60+seconds*1
    
      },
      //获取每一个歌词li的高度
      _initTops(arr)
      {
          let tops=[];
          Array.from(arr).forEach((item,index)=>{
            
            tops.push(item.offsetTop);
            
          })
          this.tops=tops;
          console.log(this.tops);
      },
      //监听任意方式得到的当前播放时间,来进行对象滚动,当index在歌词前五行和后无行时,进行居中
      //歌词和空白都是固定高度,所以可以通过歌词的行数来确定居中
      //居中方式:当前行到顶部的距离(-90是因为父元素到滑动区域的距离有90)-在多少行就可以居中
      _scrollTo(index)
      {
        console.log(index);
        if(index<5)
        {
            this.$refs.scroll.scrollTop=0;
        }else if(index>=(this.lyrs.length-5))
        {
            this.$refs.scroll.scrollTop=this.$refs.scroll.scrollHeight;
        }else{
            this.$refs.scroll.scrollTop=this.tops[index]-90-(this.tops[index+1]-this.tops[index])*4
        }
     }
  },
  computed()
  {
      song()
      {
        //   if
      }
  },
    async mounted () {
        let imgRes=await axios.get('https://api.imjad.cn/cloudmusic/?type=detail&id=346089');
        let lyricRes=await axios.get('https://api.imjad.cn/cloudmusic/?type=lyric&id=346089');
        this.imgUrl=imgRes.data.songs[0].al.picUrl;
        this.lyric=lyricRes.data.lrc.lyric;
        this.regRex(this.lyric);

    
    },
    watch:{
        lyrs()
        {
            this.$nextTick(()=>{
  
                this._initTops(this.$refs.ul.children);
                
                console.log(this.$refs.ul.children);

            })
        },
        //监听当前播放时间,和转换后的歌词时间进行对比,获得当前时间对应的歌词行数
        //第一行时间之前,直接制顶,否则会因为findIndex找不到从而获取到最后一行的索引
        time(time)
        {
            if(time<this.lyrs[0].time)
            {
                this.$refs.scroll.scrollTop=0;
                return ;
            }
            let index=this.lyrs.findIndex((item,index)=>{
                if(index<this.lyrs.length-1)
                {
                    return item.time<=time&&this.lyrs[index+1].time>=time
                }else{

                    return true;
                }

                
            })
            console.log('第二个');
            this._scrollTo(index);
            this.highlightLine=index;
        }

    },


}
</script>

<style scoped lang='less'>
    .s{
        position: relative;
        height: 500px;
        width: 100%;
        >.scale{
            position: absolute;
            right: 40px;
            top:40px;
            width: 30px;
            height: 20px;
            border:solid 1px #ccc;
            border-radius: 4px;
            text-align: center;
            line-height: 20px;
            cursor: pointer;
        }
        .b-i{
            position: absolute;
            left: 25%;
            >img{
                width: 400px;
                height: 400px;
                filter:blur(20px) opacity(0.5);
            }
        }
        .c-c{
            height: 300px;
            width: 300px;
            border-radius: 300px;
            background: #2B2C2F;
            text-align: center;
            line-height: 300px;
            position: absolute;
            left: 0;
            margin: 80px 80px;
            animation: rot 20s linear infinite;
            >img{
                height: 200px;
                width: 200px;
                border-radius: 200px;
                
            }
        }
        .on{
            animation-play-state:running;
        }
        .done{
            animation-play-state:paused;
        }

        @keyframes rot {
            from {
                transform: rotate(0deg);
            }
            to{
                transform: rotate(360deg);
            }
        }
        .c-l{
            height: 450px;
            width: 400px;
            position: absolute;
            overflow: hidden;
            right: 70px;
            top:40px;
            box-sizing: border-box;
            display: flex;
            flex-direction: column;
            .c-i{
                flex: 1;
                >p{
                    font-weight: 500;
                    font-size:20px;
                    margin-bottom:10px;
                    
                }
                margin-bottom:30px;
            }
            .c-lyr{
                flex:8;
                width: 100%;
                overflow-y:scroll ;
                >ul{
                    height: 100%;
                    list-style: none;

                    li{
                        height: 35px;
                        // padding: 7px 0;
                        line-height: 35px;
                        color: #555254;
                    }
                    .hight{
                        color:white;
                    }

                }
            }
            .c-lyr::-webkit-scrollbar {
                width: 8px;
                background-color:#FAFAFA;
            }
            .c-lyr::-webkit-scrollbar-thumb {
                border-radius: 10px;
                background-color:#E1E1E2;
            }
        }


    }
</style>
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值