效果图
在这里插入图片描述
因为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
感谢阅读