
播放进度条功能 🐞
获取进度条信息 🪲
我们在做这个功能的时候,一定要先梳理清楚HTML+CSS结构,你才知道如何去写JS效果
但不管怎么样,作为用户来说,第一时间肯定是点击或者在这个进度条上拖拽,实现快进/快退的效果~
这里我们先做点击事件, 当我们点击进度条,也就相当于点击了最外层的progressContainer元素
然后用一个叫getBoundingClientRect()方法来获取这个元素的信息~
小知识
getBoundingClientRect()方法是DOM方法
用来获取元素在浏览器视口中的位置和尺寸信息 它的返回值是一个DOMRect对象
注意: 视口一般指浏览器的可见区域, 但是不包括地址栏、工具栏这些地方~
我们可以先打印一下看看效果~
代码
//点击进度条某个位置之后计算进度条对应时间点
progressContainer.addEventListener('click', (e) => {
//获取元素在视口坐标系中的位置和尺寸信息 返回对象
var rect = progressContainer.getBoundingClientRect();
console.log(rect);
});
如图

如果你仔细看,你就能看到不管我点击这个progressContainer元素哪里,打印出来的结果都是一样的数据~
如图

仔细展开DOMRect对象, 看一下里面的东西~ 具体如下
| 属性名 | 描述 |
|---|---|
left |
元素左边框外侧到视口左侧的距离 |
right |
元素右边框外侧到视口左侧的距离 |
top |
元素上边框外侧到视口顶部的距离 |
bottom |
元素下边框外侧到视口顶部的距离 |
width |
元素的视觉宽度 |
height |
元素的视觉高度 |
x |
等同于 left |
y |
等同于 top |
注意:
这里面的属性,主要我们要留意以下width和height,它们并不是独立存储的,而是通过边界坐标计算~
width: 你其实可以理解为元素的 (右边框外侧到视口左侧的距离 - 左边框外侧到视口左侧的距离)
同理
height: 你其实可以理解为元素的 (下边框外侧到视口顶部的距离 - 上边框外侧到视口顶部的距离)
那么这意味着width和height属性其实是元素实际占据的宽高,同时还包括内容、内边距、边框
计算用户点击进度 音频条跳转到当前播放位置 🍂
那么当我们点击这个外层容器的时候,获取了它本身的数据,我们才能够往下一步进行计算!
首先要计算出用户点击这个进度条上的位置
这里需要借助事件对象中的clientX属性, 它能获取到鼠标在整个浏览器视口中的水平坐标位置~
那么我们可以用这个鼠标水平坐标位置 - 元素左边框外侧到视口左侧的距离
理解:这里我们主要计算的就是,当用户点击进度条某个位置之后, 所要知道进度条对应时间点
如图

所以,我要知道的是当用户点击进度条时,先算出点击位置相对于进度条左侧的水平距离
再用这个距离去除以进度条总宽度得到点击位置占比,最后用该占比去乘以音频总时长得到当前音频播放位置
最后把计算出来的值赋值到音频播放位置,也就是currentTime属性, 让音频跳转到对应时间点即可!
那逻辑我们梳理清楚了,代码自然也就出来了!
代码如下
//点击进度条某个位置之后计算进度条对应时间点
progressContainer.addEventListener('click', (e) => {
//获取元素在视口坐标系中的位置和尺寸信息 返回对象
var rect = progressContainer.getBoundingClientRect();
//计算当前点击的位置
var clickX = e.clientX - rect.left;
// 用这个clickX距离除以进度条总宽度得到点击位置占比,
// 最后用这个占比乘以音乐的总时长,把计算出来的结果赋值到当前音频播放位置
audio.currentTime = (clickX / rect.width) * audio.duration;//算出当前快进的音乐位置
console.log(audio.currentTime);
//同时播放音乐
audio.play();
});
如图

如果你还不明白,这里我们来举个栗子:
音频总时长就像一整个10寸的蛋糕 , 比如音频总长10秒,蛋糕就10寸,
进度条的总宽度就对应这整个蛋糕的大小
当你点进度条的某个位置,就像在蛋糕上指了想吃的那一口,先算出你指的位置离蛋糕左边沿有几寸, 对应代码里 clickX结果
重点来了,因为我们的进度条是固定的,但是我们的音频的时长不固定,那么要如何计算才能自适应进度条呢?
所以再用这个几寸除以蛋糕总寸数(进度条总宽度),就能算出你要吃的位置占整个蛋糕的比例
比如点在6寸位置,6÷10=0.6,相当于是60%, 最后用这个比例乘以音频总时长 例如: 0.6 × 10秒 =6秒
那么音频就直接跳到6秒的位置播放,就像直接吃到蛋糕 60%的位置~
现在明白了吗?!
实时更新进度条状态 🌚
我们在上面把进度条的位置计算出来之后,还要让滑块动起来呀~
这里我们需要使用到一个叫timeupdate事件 它是属于HTML5 Audio/Video 事件,大家可以去查一下文档
如图

它的作用就是可以实时帮我们追踪目前的播放位置已更改之后,所发生的状态!~
也就是说一旦音频播放的位置发生了变化,那么这个事件就会被触发!
大家可以先想一下,什么情况下,播放位置会发生变化?
是不是当我们使用play()方法开始播放的时候,它的音频位置就是一直变化的~
我们可以先测试一下看看~
audio.addEventListener('timeupdate', () => {
console.log(audio.currentTime);
});
如图

所以当我们开始播放音乐的时候,这个事件其实就已经默认一直在触发着!
那我们就可以利用这一点来让进度条的滑块动起来了!
计算方式如下:
(当前播放位置秒 / 当前音频的总秒) * 100;
逻辑分析:
音频播放时会不停触发这段代码,先确认音频有总时长~不然就不执行!
音频已播放时间 除以 音频总时长,再乘以100, 这样来算出百分之多少,
最后把进度条的宽度设为这个百分比!
当然我们这个事件函数在执行的时候,是不断执行的,所以这个百分比也会不断变化,
这样可以让我们的progressBar元素动起来,从而达到一种视觉效果~
具体代码
//使用timeupdate时间,实时更新进度条位置状态
//currentTime 设置或返回音频中的当前播放位置(以秒计)
//duration 返回当前音频的长度(以秒计)
audio.addEventListener('timeupdate', () => {
if (!audio.duration) return;
var progress = (audio.currentTime / audio.duration) * 100;
//最后把这个百分比值赋值给中间层
//然后最内层的滑块样式圆形因为绝对定位与父元素,
//会被中间层的动态宽度带过来!
progressBar.style.width = progress+'%';
});
当然这里可能有人会问,为什么不用像素,要用百分比?
用百分比是因为进度条宽度是相对的, 这样可以适配不同尺寸容器,按播放占比设百分比能精准对应音频播放进度,用像素那就要先算进度条总像素再乘占比,有点麻烦,并且适配性差!
那么做到这一步,我们的播放器也有一个大概的雏形了~
如图
