技术:React16
之前基于 vue 写了一个播放器,带各种功能,最后把自己绕死了。这次用 React 重写了个,舍弃了那些没用的功能,只保留了基本功能。并且利用媒体查询适配移动端和手机端。组件之间传值利用 props,这个播放器先供自己用,以后会抽离成为一个插件。
点击查看项目演示 (用的是 qq 音乐的 url,可能因为会资源问题有歌曲播放不出来,如果发现我会及时解决的,目前是好的)
点击进入 github 查看代码
- git clone git@github.com: capslocktao / react - music - player.git
- //安装依赖
- npm install
- //启动项目
- npm start
- //打包编译
- npm run build
API | 说明 | 类型 |
---|---|---|
info | 传入组件的歌曲数据 | Array |
onDel | 删除歌曲的回调函数 | Function |
info 接收的参数类型为一个对象数组
- render() {
- const songInfo = [{
- src: "http://fs.w.kugou.com/201712281346/32b6de4127502b0f2defb32a859b7278/G048/M00/1B/0F/EJQEAFYl4ZuAUSEVAEIa293rBH4619.mp3",
- artist: "陶喆",
- name: "Melody",
- img: "http://imge.kugou.com/stdmusic/20150718/20150718174252663587.jpg",
- id: "66575568441"
- },
- {
- src: "http://fs.w.kugou.com/201712281315/2e497482c4283748d6b3d3e7912caada/G010/M07/1F/1D/qoYBAFUKLG2AFwOuAD6hYqqxfPE635.mp3",
- artist: "周杰伦",
- name: "千里之外",
- img: "http://imge.kugou.com/stdmusic/20170728/20170728122746411503.jpg",
- id: "43245456534"
- }]
- return ( < div className = "App" > <ReactMusicPlayer info = {
- songInfo
- }
- onDel = {
- this.delSong
- }
- />
- </div > );
- }
onDel 是当删除播放列表内的歌曲时,触发的函数
- delSong(i, id) {
- //接收两个参数:i为删除的歌曲在播放列表中的位置;id为删除掉的歌曲的id
- }
播放器底层是一个 audio 标签,利用 audio 的 API 开发。用到的 API 有:
事件 API:
所有的 API: http://blog.sina.com.cn/s/blo...
首先获取 audio 对象,这里我是用 react 的 this.refs 来获取的
- let audio = this.refs.audio;
- <audio src={this.state.currentMusic.src?this.state.currentMusic.src:""} ref = "audio"></audio>
然后全局定义一个控制播放的函数,点播放调用一下,上一曲下一曲调用一下,一首歌结束后调用一下,播放列表切歌调用一下,播放列表删除歌曲调用一下。。。总之就是哪里需要哪里调用,很方便。
接下来是写进度条:由于移动端和 PC 端事件不一样,所以分别绑定了不同的事件 buffered 为缓冲进度条,played 为播放进度条
读取歌曲的缓冲进度,就要用到 audio.buffered 这个属性了,而且要在 audio 的 timeupdate 事件里实时监听,这里把播放进度条的代码也贴出来了。经过验证:利用 this.refs 获取 DOM 设置样式,不会引起组件的更新渲染。性能可能要比在 render 里函数监听 state 的变化要好,类似下边这种:
- <div className="progress-buffered" ref="buffered" style={{width:"state里计算好的长度%"}} ></div>
进度条实时变化的函数:
- audio.addEventListener('timeupdate', () = >{
- //设置播放进度条
- let playPer = audio.currentTime / audio.duration;
- this.refs.played.style.width = playPer * 100 + "%";
- //设置缓冲进度条
- let timeRages = audio.buffered;
- let bufferedTime = 0
- if (timeRages.length !== 0) {
- bufferedTime = timeRages.end(timeRages.length - 1);
- }
- let bufferedPer = bufferedTime / audio.duration;
- this.refs.buffered.style.width = bufferedPer * 100 + "%";
- //设置剩余时间
- let remainTime = parseInt(audio.duration - audio.currentTime);
- this.setState({
- remainTime: this.getTime(remainTime),
- });
- if (audio.ended) {
- this.next()
- }
- })
拖动或点击进度条,我分别对于 PC 端和移动端定义了一个事件,之后点击或者拖动的时候分别调用就可以啦:
- //PC端
- setTimeOnPc(e) {
- let audio = this.refs.audio;
- if (audio.currentTime !== 0) {
- let audio = this.refs.audio;
- let newWidth = (e.pageX - this.state.playedLeft) / this.refs.progress.offsetWidth;
- this.refs.played.style.width = newWidth * 100 + "%";
- audio.currentTime = newWidth * audio.duration;
- }
- }
- //移动端
- setTime(e) {
- let audio = this.refs.audio;
- let newWidth = (e.touches[0].pageX - this.state.playedLeft) / this.refs.progress.offsetWidth;
- this.refs.played.style.width = newWidth * 100 + "%";
- audio.currentTime = newWidth * audio.duration
- }
音量控制条的拖动和点击也是同理,就不在复述一遍了。播放列表的滑动动画是用的 ReactCSSTransitionGroup 实现的。以上这些是最核心的功能,希望对大家有所帮助。
这个小组件源于自己想写一个网站练练手,网站上会有播放音乐的功能,但是对现有的 react 音乐播放器插件不太满意,所以索性自己开发了一个,连玩带写写了两天。因为有了上次用 Vue 开发播放器的惨痛教训,这次开发本着一个原则:精简。而且在代码的组织方式上也有了更多的思考,所以这次开发还比较顺畅。喜欢的可以给点个星星~
来源: https://segmentfault.com/a/1190000012628577