{{songs.name}} {{songs.ar[0].name}}&l_微信小程序歌曲播放代码">
当前位置:   article > 正文

微信小程序 音乐播放代码(播放方式,歌词滚动) (更新优化版:添加文字颜色过渡)_微信小程序歌曲播放代码

微信小程序歌曲播放代码

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

每次滚动的时候,获取需要展示的那一行歌词的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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

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 () {
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367

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%;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/705572
推荐阅读
相关标签