uniapp实现简单的音乐播放器功能

问题描述:

创建并返回内部audio上下文来控制音乐播放
我是直接用scroll-into-view来实现的这个

<scroll-view scroll-y="true" class="gundong" :scroll-into-view="tolast" scroll-with-animation>
   <view :class="y == ind?'ind':'textarea'" v-for="(x,y) in inp1 " :key="y" :id="'tolast'+y">
    {{x}}
   </view>
  </scroll-view>

这里是歌词显示部分,我是直接往scroll-view里push然后根据时间判断当前标红歌词js代码在这里要注意歌词的格式

[ti:像风一样]
[ar:薛之谦]
[al:像风一样]
[by:]
[offset:0]
[00:00.00]像风一样 - 薛之谦 (Joker)
[00:10.70]词:薛之谦
[00:21.41]曲:薛之谦
[00:32.12]我等的模样好不具象
[00:36.16]
[00:39.79]用皮肤感受你的流向
[00:44.02]
[00:47.95]你竟然能做到带走阳光
[00:52.00]
[00:55.79]我一味的跟随过了量
[00:59.94]
[01:03.86]像风一样
[01:06.43]你靠近云都下降
[01:09.91]
[01:10.49]你卷起千层海浪我躲也不躲往里闯
[01:18.37]
[01:18.91]你不就像风一样
[01:22.35]
[01:22.94]侵略时沙沙作响
[01:26.45]
[01:27.27]再宣布恢复晴朗
[01:30.51]
[01:31.21]就好像我们两个没爱过一样
[01:38.12]
[01:45.19]曲折的夕阳负责格挡
[01:49.37]
[01:52.99]让委屈的感官无法释放
[01:57.21]
[02:01.12]最近我的伤口没生长
[02:05.13]
[02:08.97]因为我躲在没风的地方
[02:13.79]
[02:17.09]像风一样
[02:19.58]你靠近云都下降
[02:23.14]
[02:23.73]你卷起千层海浪我躲也不躲往里闯
[02:31.92]你不就像风一样
[02:35.38]
[02:35.90]侵略时沙沙作响
[02:39.23]
[02:39.91]再宣布恢复晴朗
[02:43.42]
[02:43.93]就好像我们两个没爱过一样
[02:52.82]
[02:53.56]你像风一样
[02:56.15]触摸时温柔流淌
[02:59.68]
[03:00.28]席卷我所有抵抗不急着要我投降
[03:08.41]你不就像风一样
[03:11.84]
[03:12.50]掠夺时沙沙作响
[03:16.03]
[03:16.55]可惜我自投罗网
[03:20.63]你也就没什么可骄傲的地方
[03:28.27]
[03:34.77]和风一样
[03:36.70]
[03:37.37]你离开不声不响
[03:40.87]
[03:41.73]我喜欢这种收场
[03:45.34]
[03:46.43]看上去谁也不曾亏欠过对方
[03:57.52]

歌词文件格式LRC格式

fengzhuang:function(text){
     var lines = text.split('\n')
     let that = this
      //用于匹配时间的正则表达式,匹配的结果类似[xx:xx.xx]
    let  pattern = /\[\d{2}:\d{2}.\d{2}\]/g
     // let result = [];
    while (!pattern.test(lines[0])) {
      lines = lines.slice(1);
       };
    //上面用'\n'生成生成数组时,结果中最后一个为空元素,这里将去掉
    lines[lines.length - 1].length === 0 && lines.pop();
    lines.forEach(function(v /*数组元素值*/ , i /*元素索引*/ , a /*数组本身*/ ) {
     //提取出时间[xx:xx.xx]
     var time = v.match(pattern),
      //提取歌词
      value = v.replace(pattern, '');
     //因为一行里面可能有多个时间,所以time有可能是[xx:xx.xx][xx:xx.xx][xx:xx.xx]的形式,需要进一步分隔
     time.forEach(function(v1, i1, a1) {
      //去掉时间里的中括号得到xx:xx.xx
      var t = v1.slice(1, -1).split(':');
      //将结果压入最终数组
      that.result.push([parseInt(t[0], 10) * 60 + parseFloat(t[1]), value]);
       that.result.sort(function(a, b) {
              return a[0] - b[0];
      });
     });
     for(let i = 0;i<that.result.length;i++){
      that.inp.push(that.result[i][1])
      that.inp = Array.from(new Set(that.inp))
     }
    });
   },

在这里已经将时间和歌词分开存入数组,下来就是音乐播放

const innerAudioContext = uni.createInnerAudioContext()
onLoad(option) {
   this.fengzhuang(this.value);
   innerAudioContext.src = '../../static/mp3/huxi.mp3';
   uni.setNavigationBarTitle({
    title:option.name
   })
  }

我在这个是刚进页面拿到歌词,你们也可以在点击播放的时候拿歌词

bofang:function(){
    this.lock = !this.lock
    if(this.lock){
     innerAudioContext.onTimeUpdate(() => {
       // console.log('进度更新了总进度为:' + innerAudioContext.duration + '当前进度为:' + innerAudioContext.currentTime);
       //这里是控制进度条进度
       this.duration = parseInt(innerAudioContext.duration)
       this.max = parseInt(innerAudioContext.currentTime)
       //这里是显示当前播放时间和当前音乐的总时间
       this.zongTimer = this.timeFormat(innerAudioContext.duration)
       this.zhengTimer = this.timeFormat(innerAudioContext.currentTime)
      for (var i = 0, l = this.result.length; i < l; i++) {
       // console.log(this.result[i][0])
       if (this.zhengTimer /*当前播放的时间*/ >= this.timeFormat(this.result[i][0])) {
        //显示到页面
        for(let t = 0;t<this.inp.length;t++){
         if(this.result[i][1] == this.inp[t]){
     	  //在这将歌词显示页面以及显示当前播放标红歌词
          this.inp1.push(this.inp[t]);
          this.inp1 = Array.from(new Set(this.inp1))
          this.ind = t;
         }
        }
       };
      }
      //在播放完毕恢复默认
      if(this.max == this.duration ){
           this.lock = false
           this.max = 0;
           this.duration = 100
	       this.zhengTimer = '00:00'
	       this.ind = -1
      }
     })
     innerAudioContext.play();
    }else{
     innerAudioContext.pause();
    }
   }
timeFormat:function(t){
      //分
      let min = parseInt(t/60);
      min = min < 10?'0'+min:min;
      //秒
      let sec = parseInt(t%60);
      sec = sec < 10?'0'+sec:sec;
      //返回
      return `${min}:${sec}`;
   }

在这里处理时间格式

sliderChange:function(event){
    console.log(event)
     let val = event.detail.value;
     this.zhengTimer = this.timeFormat(val)
     innerAudioContext.seek(val)
      }

控制音乐播放器进度条拉取进度,音乐快进快退我是直接用进度条控制的

watch:{
   'inp1':function(newval,oldval){
    setTimeout(()=>{
     this.tolast = 'tolast'+(newval.length-1);
    })
    
   },
   deep:true
  }

最后是控制scroll滚动条始终保持在最下方,在这里加一个setTimeout是将滑动改为异步操作,因为vue的虚拟dom导致,每次渲染的时候不能立即拿到dom元素,但是页面上有这条消息,所以加一个setTimeout变为异步就行,先渲染在滑动

前端小白分享自己经验,还请大牛多多指导,勿喷勿喷