效果图 
                
                在这里插入图片描述
             
因为html中的audio的样式不能更改,所以我们自己制作UI,做成自己想要的样子,这样要实现滑动条跟audio的双向绑定,滑动条使用了vant的组件slider,audio单向绑定到slider我们通过监听勾子 timeupdate
1 <audio   @canplay ="canplay"   preload ="preload"  @timeupdate ="updateTime"  ref ="audio"  :src ="music" > </audio > 
 
下面的这个是实时监听函数
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 updateTime(e) {        for  (var  i = 0 , l = geci.length; i < l; i++) {         if  (e.target.currentTime > geci[i][0 ]) {           this .$refs.passage.innerHTML = geci[i][1 ];         }       }        this .current = e.target.currentTime;       if  (this .count % 2  == 0 ) {          this .value = (e.target.currentTime * 100 ) / this .time;         if (isNaN (this .value)){           this .value=0          }        }        if  (this .value == 100 ) {         this .show = true ;         this .value = 0 ;         if (this .index!=this .music_list.length-1 ){           this .index=this .index+1 ;           this .music='http://localhost:3000/' +this .music_list[this .index]          new  Promise ((resolve,reject )=> {              this .$refs.audio.load()              setTimeout(() => {                resolve()              },1000 )          }).then(() => {             this .$refs.audio.play()          })                   }else {           return          }       }     }, 
 
这个函数前一部分for循环
1 2 3 4 5 for  (var  i = 0 , l = geci.length; i < l; i++) {        if  (e.target.currentTime > geci[i][0 ]) {           this .$refs.passage.innerHTML = geci[i][1 ];         }       } 
 
是歌词的处理,后面会讲到,判断
1 if  (this .count % 2  == 0 ) 
 
这个判断是解除双向绑定的冲突的,后面也会讲到,
Value是slider的百分比,我们通过当前时间乘以100在除以总时间来获得。总时间的获得我们通过canplay函数来监听,
1 2 3 4 canplay() {      this .time = this .$refs.audio.duration;      console .log(this .time)    }, 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 if  (this .value == 100 ) {        this .show = true ;         this .value = 0 ;         if (this .index!=this .music_list.length-1 ){           this .index=this .index+1 ;           this .music='http://localhost:3000/' +this .music_list[this .index]          new  Promise ((resolve,reject )=> {              this .$refs.audio.load()              setTimeout(() => {                resolve()              },1000 )          }).then(() => {             this .$refs.audio.play()          })                   }else {           return          } 
 
这一部分我们是当音乐播放完那么value是100所以我们要播放下一首歌,要先判断歌单里是否有还有歌曲,如果有则进行下一曲,然后在执行play继续播放,这边播放遇到了一个问题就是audio的play好像是个异步,所以我们load之后在等1秒钟然后在.then中执行play这样就能正常播放到下一首了。如果已经是最后一首了就return。Audio绑slider就到这。
接下来是slider绑定audio 1 2 3 4 5 6 7 8 <van-slider            @drag-end ="end"            @drag-start ="start"            class ="s"            button-size ="10px"            v-model ="value"            @change ="onChange"  /> 
 
我们通过slider的change来绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 onChange(value) {       this .$refs.audio.play()             this .show = true ;                           let  tt = Math .floor((value * this .time) / 100 );        this .$refs.audio.currentTime = tt;            }, 
 
就通过简单的计算来绑定audio的currentime,因为双向绑定所以在我们移动的时候,audio会一直影响进度条,我们slider向audio绑定的时候,audio也会向我们产生绑定这样我们的小圆点就会一直跳来跳去。所以我们就对在audio的监听函数中来进行判断是否移动slider小圆点,所以才会有之前的判断
1 2 3 4 5 6 7   start() {        this .count = (this .count + 1 ) % 2 ;      }, end() {        this .count = (this .count + 1 ) % 2 ;      }, 
 
按下小圆点和松开小圆点每次都对count进行+1取余即可,监听函数就像上面所看到的一样判断this.count为1和为0即可。
获取歌单 我们没有显示到界面上,因为懒得做,所以我们用express发送我们的歌单
后台路由
1 2 3 4 router.get('/getall' ,function (req,res,next ) {   let  result=fs.readdirSync('./public' )   res.json(result) }) 
 
就一个简单的文件读取,然后我们开启静态服务就可以根据url去访问特定的文件了。
前台接收 Axios发送请求,在created中执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 created() {     axios({       url: "http://localhost:3000/getall" ,       method: "get"      })       .then(response  =>  {         console .log(response)         this .music = 'http://localhost:3000/' +response.data[0 ];         this .music_list = response.data;                })       .catch(err  =>  {         console .log(err);       });   }, 
 
初始化music即audio的src,为第一个把url补全即可,然后把整个歌单都给music_list即可 这边我们的界面播放暂停和音量slider是否弹出是通过vue的v-show和flex布局来实现的。这边就不说了。懂得都懂。
下一首歌 1 2 3 4 5 6 7 8 9 10 11 12 13 14 next() {       if  (this .index == this .music_list.length-1 ) {         return ;       } else  {         new  Promise ((reslove, reject ) =>  {           this .index = this .index + 1 ;           this .music ='http://localhost:3000/' + this .music_list[this .index];           setTimeout(()  =>  reslove(), 1000 );         }).then(()  =>  {           this .$refs.audio.play();           this .show = true ;         });       }     }, 
 
下一首歌的函数,首先判断是否为最后一首,如果是则return,不是则index索引+1然后this.music赋值为music_list[index]然后play这边也封装在一个promise中以防万一。。。。 上一首歌一样的道理就不多说了直接上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pre() {       if  (this .index == 0 ) {         return ;       } else  {         new  Promise ((reslove, reject ) =>  {           this .index = this .index - 1 ;           this .music = 'http://localhost:3000/' +this .music_list[this .index];           setTimeout(()  =>  reslove(), 1000 );         }).then(()  =>  {           this .show = true ;           this .$refs.audio.play();         });       }     } 
 
音量的处理很简单通过代表音量slider的value值来进行赋值就行,
1 2 3 changevoice(){      this .$refs.audio.volume=(100 -this .voice)/100     }, 
 
简单的一个百分比到小数的处理,audio的音量为小数,1为最大
                
                在这里插入图片描述
              最后这个时间的处理左边的就实时获取就上面讲到的一个函数,总时间也是,然后我们写了个过滤器
1 2 3 4 5 6 7 8 9 filters: {    changetime: function (value )  {      if  (Math .floor(value % 60 ) < 10 ) {        return  Math .floor(value / 60 ) + ":0"  + Math .floor(value % 60 );      } else  {        return  Math .floor(value / 60 ) + ":"  + Math .floor(value % 60 );      }    }  }, 
 
来标准化时间,个位数就补0即可 使用就跟下面这样就行
1 <div  class ="times" > {{current|changetime}}/{{time|changetime}}</div > 
 
最后是歌词的处理,这边我只处理了一首歌。后面的处理都一样的。 我们时使用irc文件他的格式类似key,value,[时间,歌词] 就跟下面这样子一样
1 2 3 4 5 6 7 [ 0 , 'RISE 登峰造极境 - The Glitch Mob/Mako/The Word Alive'  ],     [ 3.39 , '词:英雄联盟/The Glitch Mob/Mako/The Word Alive'  ],     [ 6.79 , '曲:英雄联盟/The Glitch Mob/Mako/The Word Alive'  ],     [ 10.19 , 'Welcome to the wild no heroes and villains'  ],     [ 15.5 , "Welcome to the war we've only begun so"  ],     [ 20.84 , 'Pick up your weapon and face it'  ],     [ 23.46 , "There's blood on the crown go and take it"  ], 
 
这是我已经处理好的样子,我用node处理讲一句放在数组中形式为[时间,歌词],然后全部歌词就放在一个[[时间,歌词]]中。然后放在对audio的实时监听中,函数如下就之前上面放过了就updatetime函数中的
1 2 3 4 5 for  (var  i = 0 , l = geci.length; i < l; i++) {        if  (e.target.currentTime > geci[i][0 ]) {           this .$refs.passage.innerHTML = geci[i][1 ];         }       } 
 
这一部分然后把就这样显示了。
                
                在这里插入图片描述
             
这边歌词我没有从后端发送。因为要读文件然后输出有一些异步处理。我是直接放在了一个前端的js文件中,就像这样
1 2 3 4 5 6 7 exports.geci=[     [ 0 , 'RISE 登峰造极境 - The Glitch Mob/Mako/The Word Alive'  ],     [ 3.39 , '词:英雄联盟/The Glitch Mob/Mako/The Word Alive'  ],     [ 6.79 , '曲:英雄联盟/The Glitch Mob/Mako/The Word Alive'  ],     [ 10.19 , 'Welcome to the wild no heroes and villains'  ],     [ 15.5 , "Welcome to the war we've only begun so"  ],     [ 20.84 , 'Pick up your weapon and face it'  ], 
 
然后在组件中引入 中间的图片也不过多说,可以旋转用的css动画实现css代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 img  {  margin-top : 150px ;   border-radius : 200px ;   width : 200px ;   height : 200px ;   animation : change 6s  linear;   animation-iteration-count : infinite; } @keyframes  change {  from  {     transform : rotate (0deg );   }   to  {     transform : rotate (360deg );   } } 
 
就这样子的。 然后我这边就差不多就这么多。
心得体会 这边就差不多花了一天时间,踩了一个坑解决就花了大半天。踩得坑是koa的静态服务,如果我获取的是koa开启的静态服务的url那么audio的进度条是不能移动的导致我卡在了这边一直到最后也没解决,所以我最后使用了express来启动静态服务。其他的地方的话就一些audio的异步处理,将它放在promise中也顺利解决了。界面UI有点丑,可以有很多优化的地方,但大致功能播放音乐,音乐的切换,歌词的显示这些基本功能都实现了。
要是想要源码可以加qq547783781
         
        
    
    
        
    最后更新时间:2020-07-24 12:00:42 
  
        
        感谢阅读