摸了个简易播放器,缓冲只在播放时去做,还挺粗糙的,拖拽还没写
功能: 播放,暂停,上一首,下一首,切歌,(默认循环播放)
目录:
-
进度条
(1) timeRange
-
播放,暂停
-
上一首,下一首
-
这里其实是三条线,音频总长,缓冲,当前播放量,三条线用绝对定位就好了,给上不同的颜色
-
重点在于这三个变量,当前音频总时长,缓冲了多少,以及当前播放的位置
-
不得不说原生的JavaScript对音频视频的支持还是很强大的,具体参考这个吧http://www.w3school.com.cn/tags/html_ref_audio_video_dom.asp
this.audioPlay.duration // 返回当前音频/视频的长度(以秒计) this.audioPlay.currentTime // 设置或返回音频/视频中的当前播放位置(以秒计) this.audioPlay.buffered // 返回表示音频/视频已缓冲部分的 TimeRanges 对象
-
缓冲拿到的是timeRanges对象,这个当时懵了一下,稍微解释一下吧
-
查询数据时指定的时间戳范围或特定时间戳值。
-
MDN上讲的云里雾里的,然后是看了这篇,对应到缓冲上的解释挺合理的
length - 获得音视频中已缓冲范围的数量
start(index) - 获得某个已缓冲范围的开始位置
end(index) - 获得某个已缓冲范围的结束位置
index 是想要检索的时间范围的索引值,因此这里我们用end(0)
-
需要注意的一点是,length === 0 的情况下,说明没有缓冲,这个时候end(0)会报错,
let buffered = this.audioPlay.buffered; bufferedTime = buffered.length ? buffered.end(0) : 0;
基本工作做完了,之后可以开始播放了
-
播放,暂停
this.audioPlay.play(); // 播放 this.audioPlay.pause(); // 暂停
嗯,但这样就算完了吗?音频文件确实播放了,但是我的进度条...
-
我是不是该监听一下整个播放过程
事件 => timeupdate => 当目前的播放位置已更改时 this.audioPlay.ontimeupdate = this.listenPlay;
-
完整代码
// 点击播放,暂停 handleAudioPlay = () => { this.setState({isPlay: !this.state.isPlay}) if ( !this.state.isPlay ) { this.audioPlay.play(); this.audioPlay.ontimeupdate = this.listenPlay; } else { this.audioPlay.pause(); } }
-
之前只有一首音频文件,播放完了就没了,那现在我想播放多首,
-
需要知道当前音频是否播放完了,然后切换到下一首
this.audioPlay.ended; // true/false 当目前的播放列表已结束时 // 这里默认循环播放,当已经是最后一首时,下一首播放第一首, let idx = this.state.musicIndex === musicLists.length - 1 ? 0 : this.state.musicIndex + 1;
-
完整代码
// 监听播放进度 listenPlay = () => { this.setTimeParams(); this.audioPlay.ended && this.handleNextPlay(); } // 下一首 handleNextPlay = () => { let idx = this.state.musicIndex === musicLists.length - 1 ? 0 : this.state.musicIndex + 1; this.setMusicIndex(idx); }
然后重置一下播放器,
-
这个时候已经出bug了,第一次获取的duration有问题,点击下一首时,显示的时间是上一首的,然后我用了setTimeout延迟了一秒,再重置,发现这样居然正确了。
-
继续排查,console一下this.audioPlay,发现不用setTimeout的结果是慢了,返回的是上一首
-
百度了一下,说用oncanplay就可以了,试了一下还真的可以,
事件 => canplay => 当浏览器可以播放音频/视频时 // 重置播放器 resetPlayer = () => { this.audioPlay.oncanplay = () => { let params = { bufferedTime: 0, currentTime: 0, duration: this.audioPlay.duration } this.setState({...params}); this.state.isPlay ? this.audioPlay.play() : this.audioPlay.pause(); }; }
理解一下,当前音频还没有加载进来,因此需要通过oncanplay监听一下,在 audio 元素加载完成后 ,再去获取需要的变量值,此时才能获取到正确的 duration 值
-
下一首,切歌,就不说了,思路是通过idx获取当前播放的歌曲是哪一首