【从零到一】用HTML5+CSS+JavaScript实现一个属于自己的mp3免费音乐播放器 (4) JS交互功能(音乐进度条)

🚀 个人主页 极客小俊

✍🏻 作者简介:程序猿、设计师、技术分享

🐋 希望大家多多支持, 我们一起学习和进步!

🏅 欢迎评论 ❤️点赞💬评论 📂收藏 📂加关注

播放进度条功能 🐞
获取进度条信息 🪲

我们在做这个功能的时候,一定要先梳理清楚HTML+CSS结构,你才知道如何去写JS效果

但不管怎么样,作为用户来说,第一时间肯定是点击或者在这个进度条上拖拽,实现快进/快退的效果~

这里我们先做点击事件, 当我们点击进度条,也就相当于点击了最外层的progressContainer元素

然后用一个叫getBoundingClientRect()方法来获取这个元素的信息~

小知识

getBoundingClientRect()方法DOM方法

用来获取元素在浏览器视口中的位置尺寸信息 它的返回值是一个DOMRect对象

注意: 视口一般指浏览器的可见区域, 但是不包括地址栏、工具栏这些地方~

我们可以先打印一下看看效果~

代码

javascript 复制代码
//点击进度条某个位置之后计算进度条对应时间点
progressContainer.addEventListener('click', (e) => {
    //获取元素在视口坐标系中的位置和尺寸信息 返回对象
    var rect = progressContainer.getBoundingClientRect();
    console.log(rect);
});

如图

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

如图

仔细展开DOMRect对象, 看一下里面的东西~ 具体如下

属性名 描述
left 元素左边框外侧视口左侧的距离
right 元素右边框外侧视口左侧的距离
top 元素上边框外侧视口顶部的距离
bottom 元素下边框外侧视口顶部的距离
width 元素的视觉宽度
height 元素的视觉高度
x 等同于 left
y 等同于 top

注意:

这里面的属性,主要我们要留意以下widthheight,它们并不是独立存储的,而是通过边界坐标计算~

width: 你其实可以理解为元素的 (右边框外侧视口左侧的距离 - 左边框外侧视口左侧的距离)

同理

height: 你其实可以理解为元素的 (下边框外侧视口顶部的距离 - 上边框外侧视口顶部的距离)

那么这意味着widthheight属性其实是元素实际占据的宽高,同时还包括内容、内边距、边框

计算用户点击进度 音频条跳转到当前播放位置 🍂

那么当我们点击这个外层容器的时候,获取了它本身的数据,我们才能够往下一步进行计算!

首先要计算出用户点击这个进度条上的位置

这里需要借助事件对象中的clientX属性, 它能获取到鼠标在整个浏览器视口中的水平坐标位置~

那么我们可以用这个鼠标水平坐标位置 - 元素左边框外侧到视口左侧的距离

理解:这里我们主要计算的就是,当用户点击进度条某个位置之后, 所要知道进度条对应时间点

如图

所以,我要知道的是当用户点击进度条时,先算出点击位置相对于进度条左侧的水平距离

再用这个距离去除以进度条总宽度得到点击位置占比,最后用该占比去乘以音频总时长得到当前音频播放位置

最后把计算出来的值赋值到音频播放位置,也就是currentTime属性, 让音频跳转到对应时间点即可!

那逻辑我们梳理清楚了,代码自然也就出来了!

代码如下

javascript 复制代码
//点击进度条某个位置之后计算进度条对应时间点
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()方法开始播放的时候,它的音频位置就是一直变化的~

我们可以先测试一下看看~

javascript 复制代码
audio.addEventListener('timeupdate', () => {
    console.log(audio.currentTime);
});

如图

所以当我们开始播放音乐的时候,这个事件其实就已经默认一直在触发着!

那我们就可以利用这一点来让进度条的滑块动起来了!

计算方式如下:

javascript 复制代码
(当前播放位置秒 / 当前音频的总秒) * 100;

逻辑分析:

音频播放时会不停触发这段代码,先确认音频有总时长~不然就不执行!

音频已播放时间 除以 音频总时长,再乘以100, 这样来算出百分之多少,

最后把进度条的宽度设为这个百分比!

当然我们这个事件函数在执行的时候,是不断执行的,所以这个百分比也会不断变化,

这样可以让我们的progressBar元素动起来,从而达到一种视觉效果~

具体代码

javascript 复制代码
//使用timeupdate时间,实时更新进度条位置状态
//currentTime 设置或返回音频中的当前播放位置(以秒计) 
//duration 返回当前音频的长度(以秒计) 
audio.addEventListener('timeupdate', () => {
    if (!audio.duration) return;
    var progress = (audio.currentTime / audio.duration) * 100;  
    //最后把这个百分比值赋值给中间层
    //然后最内层的滑块样式圆形因为绝对定位与父元素,
    //会被中间层的动态宽度带过来!
    progressBar.style.width = progress+'%';  
});

当然这里可能有人会问,为什么不用像素,要用百分比?

用百分比是因为进度条宽度是相对的, 这样可以适配不同尺寸容器,按播放占比设百分比能精准对应音频播放进度,用像素那就要先算进度条总像素再乘占比,有点麻烦,并且适配性差!

那么做到这一步,我们的播放器也有一个大概的雏形了~

如图


"👍点赞" "✍️评论" "收藏❤️"
大家的支持就是我坚持下去的动力!


如果以上内容有任何错误或者不准确的地方,🤗🤗🤗欢迎在下面 👇👇👇 留个言指出、或者你有更好的想法,
欢迎一起交流学习❤️❤️💛💛💚💚


更多好玩 好用 好看的干货教程可以点击下方 关注❤️微信公众号 ❤️
说不定有意料之外的收获哦..🤗嘿嘿嘿、嘻嘻嘻🤗!
🌽🍓🍎🍍🍉🍇

相关推荐
何何____5 小时前
css变换语法介绍及案例展示
前端·css
FlyWIHTSKY6 小时前
Element Plus 中 el-row 和 el-col 的完整使用指南**
javascript·vue.js·ecmascript
摇滚侠6 小时前
基于 Redis 实现验证码登录
javascript·redis·bootstrap
时光足迹7 小时前
Tiptap之标注组件
前端·javascript·react.js
时光足迹8 小时前
Tiptap 之自定义脚注组件
前端·javascript·react.js
时光足迹8 小时前
Tiptap之造字组件
前端·javascript·react.js
小四的小六8 小时前
WebView 兼容性踩坑实录:那些让我加班的坑
javascript·webview
jump_jump8 小时前
用官方模板理解 Decky 插件:一次从模板到架构的速览
javascript·python·游戏
张元清8 小时前
React 表单处理:防抖校验、自动保存草稿与受控输入
前端·javascript·面试