基于React的音乐播放器【仿网易云音乐web】

写在前面

1、基于create-react-app脚手架创建,仿网易云音乐web端的一个音乐播放器
2、现在处于1.0版本,没有涉及到api访问,全部都是静态资源,包括音乐资源
3、因为暂时缺失api支持,歌词跟随播放滚动功能暂时缺失,相关收藏分享等业务功能缺失
4、实现了80%以上的播放器自身功能,业务性的功能,没有api,确实没办法实现
5、因为是静态音乐资源,浏览器缓存需要10-20s左右的时间,后期基于整体项目我会换成第三方api的
6、本项目包含音乐播放器主体和一个歌单功能
7、点这里是项目DEMO
8、点这里是GitHub地址,如果对你有帮助,可以给我个赞,是对我的最大鼓励

项目整体截图

react-music-component整体截图.png

播放器入参说明

传入参数 参数类型 参数详细说明 是否必须
musicList Array<object> id:唯一标识<string> ,title:歌曲名称<string> ,info:歌曲作者信息<string> ,resource:资源地址<string> ,time:歌曲持续时长(用于歌单中歌曲信息展示,播放器)<string> ,img:歌曲缩略图地址<string>
onDeleteMusic Function 删除当前歌单指定歌曲方法
onDeleteAllMusic Function 删除当前歌单全部歌曲方法

播放器实现功能

1、歌曲播放相关功能,包括:
(1)歌曲播放、暂停
(2)进度条点击,拖拽
(3)音量调整
(4)上一首歌,下一首歌,切歌功能
(5)播放模式切换(单曲循环,歌单顺序,歌单随机)
2、歌单功能,包括
(1)列表展示歌单
(2)删除全部歌单歌曲,删除歌单中某一首歌曲

核心技术点

1、H5标签audio的相关api使用
2、react基本生命周期使用,组件化思想
3、播放进度条配合audio的css绘制思路

技术点拆分

  • audio的使用
    1、react中通过ref可以控制audio,使用了三个监听方法,分别是:"canplay","timeupdate","ended",
    (1)canplay:audio准备就绪,可以开始播放音乐的时候。用于获取当前播放音乐的总时长
    (2)timeupdate:音乐播放时间时间变化监听,用于获取音乐播放当前缓存进度和播放进度,同时计算比例计算播放进度条推进进度
    (3)ended:当前音乐播放结束监听,用于自动切歌
    2、使用到的audio相关方法:
    (1)audio.buffered:获取当前audio的缓存对象,获取缓存时间的方法是:buffered.end(buffered.length - 1);
    (2)audio.duration:获取当前音乐总时长
    (3)audio.currentTime:当前播放中的音乐,当前播放到多少时刻(可以直接设置currentTime,audio会自动跳转到设置的时刻)
    (4)audio.play():音乐播放方法
    (5)audio.pause():音乐暂停方法
    (6)audio.volume:当前音乐音量设置(范围:0-1)

  • react生命周期中,判断歌单变化
    1、static getDerivedStateFromProps(nextProps, prevState)方法
    (1)歌单变化(在播放中删除了当前播放的歌曲,或者删除了其他歌曲,都是属于歌单变化的情况),需要判断新传入的歌单和之前歌单的内容对比,如果删除的音乐是当前播放的音乐,则切歌至下一首,如果删除的歌曲不是当前播放歌曲,则当前播放音乐继续正常播放,歌单变化即可
    2、componentDidUpdate(prevProps, prevState, snapshot)方法
    判断当前播放音乐变了,则需要重置播放进度条等相关UI
    3、componentDidMount() 方法
    添加audio的相关监听方法,初始化缓存条,进度条,音量等相关UI

  • 相关进度条绘制(缓存进度条、播放进度条、音量控制进度条)
    1、缓存进度条
    在audio的timeupdate监听方法中,通过audio.buffered获取到audio的缓存对象,通过当前缓存时间比例计算缓存进度条的宽度,同样是通过ref获取到缓存进度条div的DOM,直接通过计算出来的宽度设置缓存进度条的宽度,这里需要注意的一点就是缓存进度条和播放进度条是重合放置的,但是要避免缓存进度条把播放进度条给遮挡了,播放进度条的视图层应该是最高的,所以这里要使用z-index属性确保播放进度条在最上面。
    2、播放进度条
    控制原理和缓存进度条类似,只是播放进度条会在很多地方触发变化,而且有点击,拖拽等事件
    (1)点击事件
    通过onClick事件触发,通过e.pageX - this.processPlayed.getBoundingClientRect().left;,e.pageX可以获取到当前点击处距离DOM文档左侧x轴的距离,减去当前进度条左边框距离左侧x轴的距离,就能得到当前点击处相对进度条的偏移距离,这样计算对应比例,同时计算设置audio.currentTime,就能实现点击进度条控制音乐播放进度的效果
    (2)拖拽
    其实所有拖拽第三方组件的实现,都是类似的原理。
    拖拽分为几个步骤,第一步:鼠标按下,第二步:鼠标移动,第三步:鼠标松起。这里其实就是分别对应了三个时间,onMouseDown,onMouseMove,onMouseUp,方法内容和(1)的点击事件的类似,其实就是计算当前e(鼠标事件触发点)的位置,然后通过ref拿到进度条的小圆点设置style.left,拿到进度条的style.width设置进度条的宽度就可以了,但是拖拽有两个注意点需要注意:
    【注意点1】拖拽配合计算拖拽的比例的时候,需要在onMouseUp事件中设置audio的currentTime,这是音乐如果在onMouseMove及时设置了音乐的进度,会导致音乐听起来有快进和快退的感觉,这样体验感会很差,正确的做法就是在松开鼠标的时候,设置音乐进度,及时设置的只有进度条的进度
    【注意点2】onMouseUp会监听到任何情况下的鼠标抬起事件,如果是在播放器任意非点击处点击了一下,也会触发到onMouseUp,这里我先解释一下这个问题的引发原因,正常的拖拽,我们的鼠标难免会有可能偏移到进度条以外,如下图,红色示意就是我们可能会产生的鼠标的偏移,也有可能会偏下,因为进度条的长宽都是确定的,并没有覆盖到可能会产生的偏移区域,所以如果把所有拖拽时间都放到进度条上,如果鼠标产生了这种偏移,就会发生失去响应的情况,我们可以去看看其他播放器,对于这种偏移的支持都是有的,在实际应用中,这种允许内的鼠标拖拽偏移,也是允许有的,所以我们的方法必须考虑到这点,所以我的进度条上小圆点只有onMouseDown一个方法,同时在最外层整个播放器div上放了onMouseMove和onMouseUp两个事件,就是为了兼容这种拖拽偏移的问题,onMouseMove可以直接在整个播放器范围内监听鼠标移动,这里需要判断,拖拽移动如果超出了进度条最左边,就将进度设置为0,超过最右边,就将进度设置为最大宽度,而进度条上这个onMouseDown唯一的监听方法就是表示拖拽的开始,一定是从进度条最前端的小圆点开始的,这个方法中会设置一个state,标识拖拽开始,然后onMouseMove事件中会及时计算进度条宽度,最后onMouseUp会设置拖拽标识结束,同时设置进度条宽度和音乐播放进度,这里就回到我们【注意点2一开始说的问题,如果在onMouseDown不设置这个拖拽开始的标识的话,onMouseMove和onMouseUp就不知道是为了拖拽而监听的方法,所以用户在播放器内任意位置按下鼠标开始拖拽,和松开鼠标的时候,都会进行进度条位置的计算,我们本来是想兼容拖拽偏移,才把onMouseMove和onMouseUp放到播放器最外层的,这样反而导致了bug,解决的办法就是让这两个方法知道,我是在拖拽中,才进行进度计算,而拖拽的开始,一定是在进度条的小圆点上的,所以将onMouseDown放在小圆点上的,设置state,表示拖拽开始,这样就完美解决了】

拖拽鼠标偏移示例图.png

3、音量进度条
音量进度条的绘制类似播放进度条,这里不做多的赘述,需要注意的地方有两点:
(1)音乐播放条是纵向的,计算拖拽需要用pageY和getBoundingClientRect().top
(2)音乐播放条div需要注意z-index,因为会和歌单弹出画面重合,需要保证音乐控制条在歌单的上面

  • 歌单的实现
    歌单其实没有什么复杂的逻辑相关,主要是展示性的东西,因为歌单多是业务性的逻辑,业务性的逻辑,没有api配合,确实是暂时无法实现的,比如分享,收藏这些功能。所以笔者实现的功能就只有删除歌单全部歌曲和删除某一首音乐的功能,当然,也是静态功能,并不会真正从服务器上删除,删除逻辑很简单,就是处理歌单数组的事情,重点是播放器组件对于传入的新歌单的处理,我在文章上面的“react生命周期中,判断歌单变化”里面已经写了的,这里就不重复了。

写在最后

本文着重是对于技术点和思路的解析,关于audio更多的方法使用,读者可以自行去官方api查看并研究(audio的api还多着呢),另外关于播放器的实现,主色调是仿的网易云音乐web端的,但是很多UI网易云音乐都是用的background属性,笔者只好自己在阿里开源图标库里面尽量找一些风格比较统一的图标来使用,关于整体布局的实现,有参考网易云音乐web端,但是并没有照抄(吐槽:笔者是真的不喜欢一个行级块内,所有元素都用float:left来实现行级排版这种写法),虽然笔者的写法肯定不是最好的,读者自行借鉴就好。

最后的最后,如果对您有帮助,在GitHub和博客点个赞,就是对我的最大支持了,谢谢!

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容

  • 技术:React16 之前基于Vue写了一个播放器,带各种功能,最后把自己绕死了。这次用React重写了个,舍弃了...
    nero_T阅读 4,086评论 0 2
  • 前言 没有使用任何框架,只是想用最简单纯js的代码实现下 前台: Javascript+jQuery 后台: ph...
    Yangfan2016阅读 6,482评论 0 5
  • 那天,为了赶路,外套斜挎着,只顾前行。迎面一位大叔一手拽住我,喊到:你站??! 我一愣,本能把手一抬,准...
    枧文阅读 203评论 0 1
  • 作为一个正直青春期的少女,本应有自己的偶像,有自己的朋友圈,有自己的男神女神,有自己的活力,然而,我就像是一个怪胎...
    雪欧尼酱阅读 237评论 0 0
  • 书友齐州似不记,四年一季,聚散不容易。背灯和月忧忧睡,不知窗外味。 卯时惊闻微语滴,字字在心,毕竟新年至。望君以后...
    独独猪哎阅读 195评论 0 0