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变为异步就行,先渲染在滑动
前端小白分享自己经验,还请大牛多多指导,勿喷勿喷