基于React的音乐播放器,适配PC端和移动端

GameCoder
• 阅读 15741

欢迎访问个人网站:https://www.neroht.com/

基于React的适配PC端和移动端的轻量音乐播放器

技术:React16 TypeScript

点击查看效果

2020-04-02更新

播放器已经用hooks和ts重构,并发布到了npm上,扩展了许多功能,欢迎下载使用:

https://www.npmjs.com/package...

更新

基于这个音乐播放器组件写了一个简单的webapp,功能更丰富!项目github地址

演示

基于React的音乐播放器,适配PC端和移动端

演示部分页面

基于React的音乐播放器,适配PC端和移动端

写在前面

之前基于Vue写了一个播放器,带各种功能,最后把自己绕死了。这次用React重写了个,舍弃了那些没用的功能,只保留了基本功能。并且利用媒体查询适配移动端和手机端。以后会抽离成为一个插件。

点击进入github查看代码

基于React的音乐播放器,适配PC端和移动端

基于React的音乐播放器,适配PC端和移动端

功能

  • 播放,暂停
  • 上一曲,下一曲
  • 滑动或者点击歌曲进度条实现音乐的快进快退
  • 音乐剩余时间同步显示
  • 缓冲进度条
  • 播放进度条
  • 音量控制
  • 点击菜单按钮展开与隐藏播放列表
  • 播放列表内音乐播放,删除,当前播放音乐高亮显示
  • 播放音乐时封面图片旋转,暂停时停止旋转(只在PC端可查看,移动端隐藏音乐封面图片)

说明

git clone git@github.com:neroneroffy/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有:

  • audio.buffered; 返回已缓冲区域,TimeRanges
  • aduio.duration; 返回当前媒体的总时间
  • audio.currentTime; 当前播放的位置,赋值可改变位置
  • audio.paused; 是否暂停
  • audio.ended;是否结束
  • audio.play();播放
  • audio.pause();暂停
  • audio.volume;音量控制(0-1)

事件API:

  • canplay; 是否可以播放,但中途可能因为加载而暂停
  • timeupdate;播放时间更新

所有的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>

然后全局定义一个控制播放的函数,点播放调用一下,上一曲下一曲调用一下,一首歌结束后调用一下,播放列表切歌调用一下,播放列表删除歌曲调用一下。哪里需要哪里调用,很方便。

基于React的音乐播放器,适配PC端和移动端

接下来是写进度条:
由于移动端和PC端事件不一样,所以分别绑定了不同的事件
buffered为缓冲进度条,played为播放进度条

基于React的音乐播放器,适配PC端和移动端

读取歌曲的缓冲进度,就要用到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开发播放器的失败经验,这次开发本着一个原则:精简。而且在代码的组织方式上也有了更多的思考,所以这次开发还比较顺畅。喜欢的可以给点个星星~

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Stella981 Stella981
4年前
KaliTools说明书+BurpSuit实战指南+SQL注入知识库+国外渗透报告
!(https://oscimg.oschina.net/oscnet/d1c876a571bb41a7942dd9752f68632e.gif"15254461546.gif")0X00KaliLinux Tools中文说明书!(https://oscimg.oschina.net/oscnet/
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Easter79 Easter79
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
GameCoder
GameCoder
Lv1
如今白首乡心尽,万里归程在梦中。
文章
3
粉丝
0
获赞
0