原文地址:https://www.dodoblog.cn/blog?id=5be84d5c70b2b617f27a4610

这篇文章主要介绍一下博客里的这个音乐播放器是怎么写的

为了更好的表达高深的东西,还是需要先强调点简单的东西

Audio元素的属性

paused 是否暂停,不可以修改

audio.paused = true // 错误
audio.pause() // 正确

currentTime 当前播放的时间,也可以用来改变进度,以下两行代码是等价的

audio.currentTime =
audio.play()

duration 获取当前加载好的音乐的时间

loop 是否单曲循魂

mute 是否静音

volume 音量大小,数值是0 到 1

Audio元素的事件

play和pause

播放和暂停的时候触发的事件

seeking和seeked

这里的快进是时间突然到某一个点上,不是倍速播放,快进开始和快进完成分别触发一个不同事件,因为快进了可能需要加载数据,需要一点点时间

比如改变currentTime

loadstart,loadeddata和canplay

开始加,加载了一帧数据,加载到足够播放的数据

ended

结束的时候,结束了播放下一首用

还有一些事件,比如progress, volumnchange 这些方法,随便搜一下就可以知道了,大家需要自行搜去,正常情况下这些就够用了。

React播放器

参数

  <MusicPlayer
getAudio={audio => this.audio = audio}
musics={store.musicStore.currentList.songs}
/>

为了方便启用,核心的参数只有两个

getAudio,和ref一样,可以返回当前的audio元素 musics是一个音乐的列表

因为在audio元素的基础上开发,所以几乎所有的事件其实也都是在audio上通过监听获取到,所以把audio元素抛出可以减少很多配置

传入一个数组 这个数组是一个音乐列表的信息

每个对象应该包括 id,封面图链接,歌曲链接,歌词链接,歌唱家,歌曲名称

样式

我写的这个播放器是这样的,很简单的样子,基本功能都有,没有循环播放和随机播放的设置,其实也很简单

这个播放器的主要元素包括

封面,歌曲列表,名称,歌词,进度,上一首下一首,还有封面上那个钱币一样的按钮是播放暂停

然后侧面的两个按钮可以控制播放器的显示隐藏和歌曲列表的显示隐藏

具体的UI大家想象着写就好了,反正我写的也不算好看

留出那几个控制的按钮绑定事件就好了

初始化

  componentDidMount() {
const musics = this.props.musics
const audio = this.$audio.current
this.setState({
currentIndex: musics && musics.findIndex(item => item.id === window.localStorage.getItem('current-music-id')) || ,
}) audio.addEventListener('play', this.handlePlay)
audio.addEventListener('pause', this.handlePause)
this.props.getAudio && this.props.getAudio(audio)
}

初始化的时候,

1. 添加了事件监听,这样当外部改变audio的状态也会改变播放器组件的状态

2. 获取localstorage里的音乐,这个很友好,可以刷新仍然是那一首歌

3. 抛出audio元素

播放和暂停

  handlePlay = () => {
const music = this.props.musics[this.state.currentIndex]
const audio = this.$audio.current this.handleLoadLrc()
this.setState({ paused: false }) window.localStorage.setItem('current-music-id', music.id)
audio.play(audio.currentTime) this.timer = setInterval(() => {
const { currentTime, duration } = audio
this.setState({ currentTime, duration })
}, )
} handlePause = () => {
this.setState({ paused: true })
this.$audio.current.pause()
this.timer && clearInterval(this.timer)
}

注意

1. currentIndex表示当前的播放的音乐的index

2. 我们设置了pause的属性 是记录播放器的当前状态,audio的状态改变不能实时反应去渲染dom,所以需要用自己的state记录。

3. play需要传入当前的audio时间,这样暂停播放不会重新开始,而切换后currentTime也会归0

4. 动态记录了currentTime和duration,并且用计时器不对获取,也是因为我们并没有办法实时获取时间反映到进度条上

上一首,下一首和切换

  handleNext = () => {
let currentIndex = this.state.currentIndex +
if (currentIndex >= this.props.musics.length) {
currentIndex =
} this.setState({currentIndex }, this.handlePlay)
} handlePrev = () => {
let currentIndex = this.state.currentIndex -
if (currentIndex < ) {
currentIndex = this.props.musics.length -
} this.setState({currentIndex }, this.handlePlay)
} handleToggle = currentIndex => {
this.setState({currentIndex }, this.handlePlay)
}
 

上一首就是index - 1然后播放,如果index = 0 那么index为最后一个

下一首就是index +1然后播放,如果index已经最大 那么index重置0

切换就是接受一个index 改变后播放

这三个超级简单,不多解释

快进

  handlePlayFrom = e => {
const audio = this.$audio.current
const { left, width } = e.target.getBoundingClientRect()
const clickPos = (e.clientX - left) / width
const time = audio.duration * clickPos
if (!time) return false
audio.currentTime = time
}

这个稍微考验些关于dom位置判断的功底

通过获取进度条的宽度,点击的位置,然后计算出一个进度的百分比,最后根据这个百分比和总的音乐时长计算出点击点的时间

加载歌词

handleLoadLrc = () => {
const request = new XMLHttpRequest();
const url = this.props.musics[this.state.currentIndex].lrc
request.open('GET', url, true);
request.onload = () => {
this.lyricStr = request.response
}
request.send();

播放的时候回去加载歌词,就是一个ajax请求,返回的歌词一般都是这样的格式

看起来像个数组,其实是一个字符串,然后我们可以通过正则将其拆分成一个时间 歌词一一对应的数组,这个是最麻烦的一点,但其实并没有什么技术复杂度,主要就是处理字符串通过split拆分成数组就好

然后根据当前的currentTime获取需要显示的那句歌词

不细节分析了,有需要的可以在我的github上看

切换歌单

  componentDidUpdate(nextProps) {
if (nextProps.musics !== this.props.musics) {
this.setState({ currentIndex: }, this.handlePlay)
}
}
当音乐列表发生改变的时候,重新播放就好了

播放器的显示隐藏

动态添加一个class去隐藏整个播放器就好啦,fixed定位,很容易搞定的

播放器的基本功能就这么多啦,当然还有一些,比如设置播放模式,依次还是随机,是否单曲循环等等,这些其实都很简单。

具体的代码

戳这里 获取播放器的代码,有需要的自取

总结,在audio元素的基础上开发是比较简单的,但是这也有很多不好的地方,比如说,别人找到audio元素,然后加一个controls属性,就可以下载音乐了。

真正强大的是Audio API,W3C提供了操作音频的一系列api 可以实现更好的音频buffer 播放效果,甚至通过analyser分析音频进行mix混音以及音乐效果的改变。

还可以写好玩的动画效果,比如

这些的前提当然是需要对音乐有一定的了解,有兴趣的小伙伴可以研究一下哦,这是很有趣的一个方向。

Audio 标签的使用和自己封装一个强大的React音乐播放器的更多相关文章

  1. 一个简单的ipfs音乐播放器的实现

    IPFS音乐播放器 IPFS相关 IPFS第一次亲密接触 什么是IPFS IPFS对比HTTP/FTP等协议的优势 IPFS应用场景 -移动数据 交易 路由 网络 定义数据 命名 使用数据 具体场景; ...

  2. 一个简单的Android音乐播放器

    Android小白的期末作业 Android期末项目,仅用作学习使用,在线音乐部分只获取了网易云热歌榜,API来自鼻子亲了脸 传送门: GitHub 参考: anddiencn 实现功能 展示出本地的 ...

  3. 一个功能齐全的IOS音乐播放器应用源码

    该源码是在ios教程网拿过来的,一个不错的IOS音乐播放器应用源码,这个是我当时进公司时 我用了一晚上写的  图片都是在别的地方扒的,主要是歌词同步,及上一曲,下一曲,功能齐全了 ,大家可以学习一下吧 ...

  4. 用<audio>标签打造一个属于自己的HTML5音乐播放器

    上一章节,我们刚刚讲了<video>标签,今晚,我们讲的是<audio>标签,这两个东东除了表示的内容不一样以外,其他的特性相似的地方真的太多了,属性和用法几乎一样,也就说,如 ...

  5. 一个基于H5audio标签的vue音乐播放器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 4个小时实现一个HTML5音乐播放器

    技术点:ES6+Webpack+HTML5 Audio+Sass 这里,我们将一步步的学到如何从零去实现一个H5音乐播放器. 首先来看一下最终的实现效果:Demo链接 接下来就步入正题: 要做一个音乐 ...

  7. Swift - 制作一个在线流媒体音乐播放器(使用StreamingKit库)

    在之前的文章中,我介绍了如何使用 AVPlayer 制作一个简单的音乐播放器(点击查看1.点击查看2).虽然这个播放器也可以播放网络音频,但其实际上是将音频文件下载到本地后再播放的. 本文演示如何使用 ...

  8. 如何用vue打造一个移动端音乐播放器

    写在前面 没错,这就是慕课网上的那个vue音乐播放器,后台是某音乐播放器的线上接口扒取,虽然这类项目写的人很多,但不得不说这还是个少有的适合vue提升的好项目,做这个项目除了想写一个比较大并且功能复杂 ...

  9. 记一次酷狗音乐API的获取,感兴趣的可以自己封装开发自己的音乐播放器

    1.本教程仅供个人学习用,禁止用于任何的商业和非法用途,如涉及版权问题请联系笔者删除. 2.随笔系作者原创文档,转载请注明文档来源:http://www.cnblogs.com/apresunday/ ...

随机推荐

  1. FIR和IIR设计指标

  2. 13-Ubuntu-查阅终端命令版本信息和帮助信息

    查看版本信息: 终端命令 --version 查看帮助信息: 终端命令 --help 注: 待查阅的命令 后面有两个减号-- 例:查看终端命令ls的版本和帮助信息 ls --version ls -- ...

  3. codeforces round#524 C. Masha and two friends /// 矩形切割

    题目大意: 给定n行m列的黑白棋盘如下 给定矩形的左下点x1 y1和右上点x2 y2将这个区域都涂成白色 再给定矩形的左下点x3 y3和右上点x4 y4将这个区域都涂成黑色 求最后棋盘内有分别多少个白 ...

  4. vue项目使用history模式打包应该注意的地方

    1.在config/index.js中将assetsPublicPath原来的’/‘修改为‘./’. build: { env: require('./prod.env'), index: path. ...

  5. ES6 学习 -- Promise对象

    1.promise含义:可以将promise对象看成是一个容器,它保存着未来才会结束的某个事件(一般是异步操作事件)的结果,各 种异步操作都可以用promise对象来处理promise的特点:(1)p ...

  6. js原型继承四步曲及原型继承图

    一:js原型继承四步曲 //js模拟类的创建以及继承 //动物(Animal),有头这个属性,eat方法 //名字这个属性 //猫有名字属性,继承Animal,抓老鼠方法 //第一步:创建父类 fun ...

  7. log-slave-updates参数

    从库做为其他从库的主库时 log-slave-updates参数是必须要添加的,因为从库要作为其他从库的主库,必须添加该参数.该参数就是为了让从库从主库复制数据时可以写入到binlog日志,为什么要用 ...

  8. delphi 用户可以点击格式修改进行模板修改

    过程 TlistRepAdd.Btn_GCListRepEditClick窗口 TlistRepAdd 补打流程单 1. 给用户权限 呈现出格式修改按钮 procedure TlistRepAdd.B ...

  9. 【JZOJ4665】数列

    description analysis 水法又\(n\)方二十万-- 可以先离散化,然后枚举起点,枚举向下扫 同一个数出现过或模数不相同就\(break\),注意\(k\)不够顶替还是有可能存在解不 ...

  10. thinkphp 异常处理

    和PHP默认的异常处理不同,ThinkPHP抛出的不是单纯的错误信息,而是一个人性化的错误页面,如下图所示: 只有在调试模式下面才能显示具体的错误信息,如果在部署模式下面,你可能看到的是一个简单的提示 ...