原文地址: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. windows下装LINUX后,进不了系统

    在网上找了一款叫"DisckGenius"的软件,运行后选“硬盘”/“重建主引导记录(MBR)”,然后重启,就正常了. 还有系统盘最好是FAT32格式的.

  2. vue axios springBoot 跨域session丢失

    前端: 在引入axios的地方配置 axios.defaults.withCredentials=true,就可以允许跨域携带cookie信息了,这样每次发送ajax请求后,只要不关闭浏览器,得到的s ...

  3. shell 一些命令(转)

    shell 一些命令(转) https://www.cnblogs.com/amei0/p/8041989.html 参考文档 http://man.linuxde.net/ 一.awk 求和 awk ...

  4. Linux下mysql实现远程连接

    首先明白一点并不是mysql禁止远程连接,而是MYSQL的账号禁止远程连接.可能觉得我有点咬文嚼字了,不过我感觉分清这点还是很重要的.默认情况下,所有账号都是禁止远程连接的.在安装MYSQL的时候,在 ...

  5. mysql 复制原理详解

    http://www.cnblogs.com/kristain/articles/4142970.html

  6. 取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏

    取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏,在MainActivity中添加以下代码: getWindow().clearFlags(WindowManager.LayoutP ...

  7. python中的 += 语法的使用

    python中有个缩略的写法,如下 a = a +1 等同于 a +=1 发现了一个有趣之处,+=的写法中间不能有空格,否则报错,测试如下 Python 3.7.1 (v3.7.1:260ec2c36 ...

  8. [JZOJ4331] 【清华集训模拟】树

    题目 题目大意 给你一棵带点权的树,求将树变成一堆不相交的链,而且这些链的权值和非负的方案数. 正解 显然这道题是个\(DP\). 首先求个前缀和\(sum\). 为了后面讲述方便,我这样设:\(f_ ...

  9. 【JZOJ6367】工厂(factory)

    description 大神 wyp 开了家工厂,工厂有 n 个工人和 p 条流水线. 工厂的工人都是睡神,因此第 i 个工人只会在 si 至 ti 时刻才会工作. 每个工人都会被分派到一条流水线上, ...

  10. AYITOJ-括号序列-栈的入门

    题目描述 给定一个由括号组成的字符串 问其是否为一个合法的括号序列 合法的括号序列的定义如下 1. 空字符串是合法的括号序列 2. 若字符串A是合法的括号序列, 那么{A},[A],(A)也是合法的括 ...