自动滚动时,歌词太长造成了很长的偏移,如何解决:

每次滚动的时候,获取需要展示的那一行歌词的dom节点高度位置,直接滚动到当前节点的位置就可以了。
公式:需要滚动的位置 = dom节点位置 - 歌词区域高度 / 2 - dom节点的高度/2。

类似功能:滚动到中部

项目源码:
https://download.csdn.net/download/qq_42740797/15542837

效果图:

在这里插入图片描述

wxml:

<view class="container flex-align">
	<view style="text-align:center;position:relative;" class="box">
		<view style="color:white;">{{songs.name}}</view>
		<view style="color:#ddd;" class="f12">{{songs.ar[0].name}}</view>
		<image src="../../images/play/download.png" style="height:60rpx;width:60rpx;" class="download" bindtap="download" />
	</view>
	<view class="flex-1 flex-center" wx:if="{{isLrc==false}}" bindtap="isLrc">
		<image src="{{songs.al.picUrl}}" class="img {{isPlay===false?'pause':''}}" />
	</view>
	<!--歌词-->
	<view wx:else class="flex-1 flex-center z" bindtap="isLrc" style="position:relative;" >
		<view wx:if='{{isScroll}}' class="line flex-box" style="width:100%;color:white;border:1px solid rgba(244,244,244,0.2);">
			<view style="margin:0rpx 20rpx;" class="f12 flex-center">{{locationShowTime}}</view>
			<view class="flex-1" style="color:red;height:2rpx;width:100%;background:green;"></view>
			<view style="margin:0rpx 20rpx;" class="flex-center"><image src="../../images/play/locationTime.png" style="height:40rpx;width:40rpx;z-index:999;" catchtap="playScroll"/></view>
		</view>
		<scroll-view scroll-y style="height:600rpx;" scroll-with-animation scroll-top="{{locationIndex*27}}" bindscroll="scroll" bindtouchstart="touchstart" bindtouchend="touchend">
			<view style="height:284rpx;"></view>
			<view wx:for="{{lrc}}" wx:key="index" class="f14" style="text-align:center;margin:20rpx 0rpx;color:#ccc;"><text style="position: relative;">{{item}}<text wx:if="{{location===index}}" class="hover" style="animation: test {{timeLen}}s;">{{item}}</text></text></view>
			<view style="height:300rpx;"></view>
		</scroll-view>
	</view>
	<!--进度条-->
	<view class="flex-box box" style="color:white;">
		<view class="flex-center">{{nowTime}}</view>
		<view class="flex-1">
			<slider min="{{min}}" max="{{max}}" block-size="12" value="{{value}}" bindchange="slider" bindchanging="sliderNow"></slider>
		</view>
		<view class="flex-center">{{totalTime}}</view>
	</view>
	<!--播放控件-->
	<view class="flex-box menu">
		<view>
			<image wx:if="{{categoryActive===0}}" bindtap="toggleCategory" src="../../images/play/list.png" style="height:60rpx;width:60rpx;" />
			<image wx:if="{{categoryActive===1}}" bindtap="toggleCategory" src="../../images/play/rand.png" style="height:60rpx;width:60rpx;" />
			<image wx:if="{{categoryActive===2}}" bindtap="toggleCategory" src="../../images/play/single.png" style="height:60rpx;width:60rpx;" />
		</view>
		<view>
			<image src="../../images/play/back.png" style="height:80rpx;width:80rpx;" bindtap="back" />
		</view>
		<view>
			<image wx:if="{{isPlay===false}}" bindtap="togglePlay" src="../../images/play/play.png" style="height:100rpx;width:100rpx;" />
			<image wx:else bindtap="togglePlay" src="../../images/play/pause.png" style="height:100rpx;width:100rpx;" />
		</view>
		<view>
			<image src="../../images/play/next.png" style="height:80rpx;width:80rpx;" bindtap="next" />
		</view>
		<view>
			<image wx:if="{{isCollect===false}}" bindtap="toggleCollect" src="../../images/play/collect.png" style="height:60rpx;width:60rpx;" class="move" />
			<image wx:else bindtap="toggleCollect" src="../../images/play/collectActive.png" style="height:60rpx;width:60rpx;" class="move" />
		</view>
	</view>
</view>
<!--背景图片-->
<view class="bgImage">
	<image src="{{songs.al.picUrl}}" />
</view>

js:

import api from "../../http/api"
import dayjs from "../../lib/dayjs.min.js"
let bg=wx.getBackgroundAudioManager();//背景音频管理器
let timeId='';//定时器
let lineTimeId='';//水平线定时器
let isDelete=false;//是否删除开启的定时器
Page({
  data: {
    index:-1,//下标 歌曲信息
    ids:[],//歌曲id
    songs:{},//歌曲详情
    musics:{},//歌曲url
    lrc:{},//歌曲歌词
    //控件属性
    isSlider:false,//是否正在拖动进度条
    nowTime:"00:00",//目前进度时间
    totalTime:"00:00",//总长度时间
    min:0,//进度条开始
    max:0,//进度条结束
    value:0,//进度条
    category:[],//播放方式
    categoryActive:0,//当前播放方式 0:顺序播放 1:随机播放 2:单曲循环
    isPlay:true,//是否播放
    isCollect:true,//是否收藏
    //以下歌词
    isLrc:true,//是否显示歌词
    lrcArr:[],//歌词定位数组 时间
    location:0,//歌词滚动位置
    locationIndex:0,//
    locationValue:0,//歌词滚动具体位置
    locationTime:0,//歌词定位时间
    locationShowTime:'00:00',//歌词定位显示时间
    isScroll:false,//滚动显示水平线
    timeLen:-1,//文字过渡时间
  },
  //歌词触碰开始
  touchstart(e){
    console.log("触摸开始",e);
    this.setData({
      isScroll:true
    });
    isDelete=false;
    if(lineTimeId){
      clearTimeout(lineTimeId);
      lineTimeId='';
    }
  },
  //歌词触碰结束
  touchend(e){
    isDelete=true;
    console.log("触摸结束",e);
    if(lineTimeId!='')return;
    lineTimeId=setTimeout(()=>{
      if(isDelete===true){
        this.setData({
          isScroll:false
        });
        lineTimeId='';
      }
    },4000);
  },
  //歌词滚动
  scroll(e){
    if(this.data.isScroll){
      let i=parseInt(e.detail.scrollTop/27);
      if(!this.data.lrcArr[i])return;//空白区域,没有时间不执行
      console.log("滚动",e.detail.scrollTop,this.data.lrcArr[i]);//歌词的间隔区间为27
      this.setData({
        locationTime:this.data.lrcArr[i],
        locationShowTime:dayjs(this.data.lrcArr[i]*1000).format("mm:ss")
      });
    }
  },
  //歌词拖动播放
  playScroll(e){
    console.log("拖动播放",e);
    let value=this.data.locationTime;
    bg.seek(value);
    this.setData({
      isScroll:false,
      isPlay:true
    });
    this.update();
  },
  //切换是否显示歌词
  isLrc(e){
    this.setData({
      isLrc:!this.data.isLrc
    });
  },
  //下载音乐
  download(e){
    console.log(e);
    wx.setClipboardData({
      data: this.data.musics.url,
      success:res=>{
        console.log(res.data);
        wx.hideToast();
        wx.showToast({
          title: '已复制链接',
        })
      }
    })
  },
  //进度条拖动
  sliderNow(e){
    console.log(e);
    let nowTime=dayjs(e.detail.value*1000).format('mm:ss');
    this.setData({
      nowTime:nowTime,
      isSlider:true
    });
  },
  //进度条
  slider(e){
    console.log(e);
    let value=Number(e.detail.value);
    let nowTime=dayjs(e.detail.value*1000).format('mm:ss');
    this.setData({
      value:value,
      nowTime:nowTime,
      isSlider:false
    });
    console.log(typeof(value),value);
    bg.seek(value);
  },
  //上一首
  back(){
    let index;
    if(this.data.categoryActive===0){//顺序播放
      index=this.data.index-1;
      if(index<0){//第一首处理
        index=this.data.ids.length-1;
      }
    }else if(this.data.categoryActive===1){//随机播放
      index=parseInt(Math.random()*this.data.ids.length);
    }else{//单曲循环
      index=this.data.index;
      bg.stop();
    }
    console.log(index);
    this.setData({
      index:index,
      isPlay:true
    });
    this.getData();//重新获取音乐
  },
  //下一首
  next(){
    let index;
    if(this.data.categoryActive===0){//顺序播放
      index=this.data.index+1;
      if(index===this.data.ids.length){//最后一首处理
        index=0;
      } 
    }else if(this.data.categoryActive===1){//随机播放
      index=parseInt(Math.random()*this.data.ids.length);
    }else{//单曲循环
      index=this.data.index;
      bg.stop();
    }
    console.log(index);
    this.setData({
      index:index,
      isPlay:true
    });
    this.getData();//重新获取音乐
  },
  //播放音乐
  playMusic(){
    console.log("播放",this.data.musics.url,this.data.songs.name);
    bg.src=this.data.musics.url;
    bg.title=this.data.songs.name;
    //设置进度条
    console.log("进度条",bg.duration);
  },
  //切换播放方式
  toggleCategory(e){
    // console.log(e);
    let i=this.data.categoryActive+1;
    if(i>2)i=0;
    this.setData({
      categoryActive:i
    });
  },
  //切换播放
  togglePlay(e){
    console.log(e);
    this.setData({
      isPlay:!this.data.isPlay
    });
    if(this.data.isPlay){
      bg.play();
    }else{
      bg.pause();
    }
  },
  //切换收藏
  toggleCollect(e){
    console.log(e);
    this.setData({
      isCollect:!this.data.isCollect
    });
  },
  //获取音乐数据
  getData(){
    let id=this.data.ids[this.data.index];
    console.log(id);
    //获取歌曲详情
    api.songDetail(id).then(res=>{
      console.log("歌曲详情:",res);
      this.setData({
        songs:res.songs[0]
      });
      //获取音乐url
      api.songUrl(id).then(res=>{
        console.log("歌曲音乐url:",res);
        this.setData({
          musics:res.data[0]
        });
        this.playMusic();//播放音乐
        wx.hideLoading();
      }).catch(err=>{
        console.log(err);
      });
    }).catch(err=>{
      console.log(err);
    });
    //获取歌词 
    api.lyric(id).then(res=>{
      console.log("歌曲歌词 :",res);
      let str=res.lrc.lyric;
      let lrcArr=[];
      let arr=[];
      str=str.split(/\n/g);
      str.map(item=>{
        let i=item.match(new RegExp("\\[[0-9]*:[0-9]*.[0-9]*\\]","g"));
        if(i){
          i=i[0].replace('[','').replace(']','')
          let time=Number(i.split(':')[0]*60)+Number(i.split(':')[1].split('.')[0]);//毫秒:+Number(i.split(':')[1].split('.')[1]);         01:12.232  ['01','12.232'] ['12','232'] 
          // console.log(time,dayjs(time).format('mm:ss')); 
          lrcArr.push(time);
          arr.push(item.replace(new RegExp("\\[(.*)\\]","g"),""));
        }
      });
      //去空
      let a1=[],a2=[];
      for(let i=0;i<arr.length;i++){
        if(arr[i]&&lrcArr[i]){//当前是否有歌词
          a1.push(arr[i]);
          a2.push(lrcArr[i]);
        }
      }
      arr=a1,lrcArr=a2;
      console.log(arr);
      console.log(lrcArr);
      this.setData({
        lrc:arr,
        lrcArr:lrcArr
      });
      wx.hideLoading();
    }).catch(err=>{
      console.log(err);
    });
  },
  //定时器更新
  update(){
    if(!this.data.isPlay||this.data.isSlider)return;
      let nowTime=bg.currentTime;
      let totalTime=bg.duration;
      let value=bg.currentTime;
      let max=bg.duration;
      if(nowTime&&totalTime){//都有数据
        //处理歌词当前位置
        // let len=0;//歌词排除为空的下标
          for(let i=0;i<this.data.lrcArr.length;i++){
            if(nowTime>this.data.lrcArr[this.data.lrcArr.length-1]){//最后的歌词
              this.setData({
                location:this.data.lrcArr.length
              });
              break;
            }
            console.log(nowTime,this.data.lrcArr[i]);
            if(nowTime>=this.data.lrcArr[i]&&nowTime<this.data.lrcArr[i+1]){
              console.log("歌词滚动");
              this.setData({
                location:i
              });
              break;
            }
          }

        //设置滚动
        if(this.data.isScroll===false){
          if(this.data.locationIndex!=this.data.location){
            this.setData({
              timeLen:this.data.lrcArr[this.data.location+1]-this.data.lrcArr[this.data.location]
            });
          }
          this.setData({
            locationIndex:this.data.location
          });
        }
        //处理显示
        totalTime=dayjs(totalTime*1000).format('mm:ss');
        nowTime=dayjs(nowTime*1000).format('mm:ss');
        console.log("时间2:",totalTime,nowTime);
        this.setData({
          nowTime:nowTime,
          totalTime:totalTime,
          max:max,
          value:value
        });
      }
  },
  onLoad: function (options) {
    console.log(options.index,options.ids);
    let ids=options.ids.split(',');//字符串拆分
    console.log(ids);
    this.setData({
      index:Number(options.index),
      ids:ids
    });
    this.getData();
    //背景音频
    bg.onEnded(()=>{
      console.log("播放完毕。");
      this.next();
    });
    bg.onPause(()=>{
      console.log("暂停播放");
      this.setData({
        isPlay:false
      });
    });
    bg.onPlay(()=>{
      console.log("开始播放");
      this.setData({
        isPlay:true
      });
    });
    bg.onTimeUpdate(()=>{
      // console.log("播放进度更新");
      // this.update();
    });
  },
  onReady: function () {
  },
  onShow: function () {
      //设置进度条
    timeId=setInterval(()=>{
      this.update();
    },500);
  },
  onHide: function () {
  },
  onUnload: function () {
    //销毁定时器
    clearInterval(timeId);
  },
  onPullDownRefresh: function () {
  },
  onReachBottom: function () {
  },
  onShareAppMessage: function () {
  }
})

wxss:

.container{
  position: absolute;
  width: 100%;
  height:100%;
  background:rgba(0,0,0,0.2);
  /* border: 1px solid red; */
}
.container>view{
  /* border: 1px solid red; */
}
.download{
  position: absolute;
  
  right:20rpx;
  top: 20rpx;
}
.img{
  width:500rpx;
  height:500rpx;
  border-radius: 50%;
  border: 20rpx solid rgba(255,255,255,0.4);
  -webkit-animation: rotate 10s linear infinite;
  
}
.pause{
  animation-play-state:paused;
-webkit-animation-play-state:paused; /* Safari 和 Chrome */
}
.menu{
  margin:50rpx 0rpx;
}
.menu>view{
  flex:1;
  display: flex;
  justify-content: center;
  align-items: center;
}
.bgImage{
  filter:blur(20px);
  position:absolute;
  height:100%;
  width:100%;
  z-index: -1;
}
.bgImage>image{
  height:100%;
  width:100%;
}
.move:active {
  animation-delay: -6s;
  animation: heartBeat 2s;
}
.line{
  position: absolute;
  top:50%;
}
.z{
  
}
@keyframes rotate {
  0%{
      transform:rotate(0deg);
      -ms-transform:rotate(0deg);     /* IE 9 */
      -moz-transform:rotate(0deg);    /* Firefox */
      -o-transform:rotate(0deg);
  }
  100% {
      transform:rotate(360deg);
      -ms-transform:rotate(360deg);   /* IE 9 */
      -moz-transform:rotate(360deg);  /* Firefox */
      -o-transform:rotate(360deg);
  }
}

@-webkit-keyframes rotate {
  0%{
      -moz-transform:rotate(0deg);
  }
  100%{
      -moz-transform:rotate(360deg);
  }
}

/*文字过渡*/
.hover {
  position: absolute;
  top: 0;
  left: 0;
  color: red;
  overflow: hidden;
  width: 100%;
  white-space: nowrap;
}

@keyframes test {
  from {
      width: 0%;
  }
  to {
      width: 100%;
  }
}
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐