·悄然 - 2024-12-17 15:19
·悄然 - 2024-12-15 15:12
·悄然 - 2024-12-9 12:32
·飞飞 - 2024-12-9 12:31
·小希 - 2024-12-7 11:50
·飞飞 - 2024-12-5 15:53
·飞飞 - 2024-12-3 16:42
·悄然 - 2024-12-3 16:41
·飞飞 - 2024-12-1 18:27
保姆级range进度条音频播放器开发教程(四)
到第三节 保姆级range进度条音频播放器开发教程(三) 的时候,我们的range进度条播放器不仅有模有样,还与音乐的播放/暂停智能联动,算是成功的作品了。下一步,我们想让 range 滑杆发挥更大的作用,即可以通过拖曳滑杆的滑块改变音频的播放位置,而不仅仅是显示音乐的播放进度。这将是本节的核心内容。
range滑块自身是可以随意拖动的,不过,它现在由 audio 的 timeupdate 监听事件控制着,在音乐播放的时候,拖曳滑块并不管用,timeupdate 监听事件总是会将其复位到音频的当前播放位置。我们得设计一个机制,以实现如下功能:当用户想要改变播放位置时,我们让 timeupdate 监听事件暂停工作,把滑杆滑块的滑动权交出来,待用户改变音乐的播放位置操作结束了再将滑动权还给它。
这需要引入一个布尔变量,我们用 mseek 来命名,m 还是music,seek 本意查找,这里指用户查找新的播放位置(mseek只是一个命名,可以随意)。当 mseek 为真(true),表明用户要进行进度调节操作,timeupdate 监听事件就先不驱动 range 的运行,待用户操作完毕,即当 mseek 为假(false)之时,timeupdate 监听机制继续工作。看看怎么声明 mseek 变量:
var mseek = false;
var 是 JS 声明变量的关键词,除它以外,还有 let,const,它们的区别先不用理睬,我们就用 var 好了。var 之后紧接着一个自定义变量名称(彼此间有空格),然后用等号给它一个值,布尔变量非真即假,真表示为 true,假表示为 false,我们上面给 mseek 的赋值是 false,这又为什么呢?因为,开始的时候,用户没有去操作进度调整,这时呢,timeupdate 监听机制要驱动 range 的进度运行。对应地,audio 的 timeupdate 监听事件我们要给它添加一个条件语句:
var mseek = false;
aud.addEventListener('timeupdate', () => {
if (!mseek) mprog.value = aud.currentTime / aud.duration * mprog.max;
});
注意红色代码,它就是条件语句,if (!mseek) 相当于 if (mseek !== true)、等同于 if (mseek === false) ,就是如果 mseek 变量不为真之意,具体来说是,如果用户没有手动调节进度之时。感叹号 ! 在这里表示 mseek 的否定,三个等号表示绝对等于,感叹号加两个等号表示绝对不等于,这都太复杂,所以我们用 !mseek 来表示不为真即不等于真。if (!mseek) 语句加持后,timeupdate监听事件就更加聪明了,它指挥进度条的权限完全依赖于 mseek 变量值的变化:为假时驱动进度条的运行,为真时是用户正在手动调节进度,就不瞎掺和来着。这样,我们下一步要做的就是,如何获知用户正在调节进度了。
用户调节播放进度,需要在 range 滑块上按下鼠标左键,JS对此有个对应的处理事件,叫 onmousedown,意思是鼠标左键按下之时,可用于任意可视元素。页面上鼠标按下的动作频繁,我们只需针对 input 的 range 控件,它的 id 为 mprog,在它上面按下鼠标左键时:
mprog.onmousedown = () => mseek = true;
意思是,mprog 元素之上,当鼠标左键按下时,执行 mseek = true 语句,就是,令 mseek 布尔变量值为真。mseek 为真,timeupdate 监听事件就不再驱动 mprog 的运行,用户就可以随意拖动滑杆上的滑块了。
用户调节完毕,mseek 的值还需要变回假,以便进度条能够显示当前正确的播放位置。这得用到JS的鼠标松开事件,onmouseup,同样地,我们只管 mprog 的鼠标松开事件:
mprog.onmouseup = () => mseek = false;
鼠标键松开时就是需要改变音乐播放位置的时候,这又用到 input type="range" 元素即滑杆的 onchange 或 oninput 事件,这两个事件都表示滑杆 value 值改变之时,我们选用 onchange 事件(其实用哪个都行),它在鼠标左键或键盘方向键松开之时触发,代码如下:
mprog.onchange = () => /* 做点什么 */;
“做点什么”又是一个要处理的一个问题,这只是数学问题,它还是 aud.duration、aud.currentTime、mprog.vallue、mprog.max 即音频控件总时长、当前播放时间和滑杆当前值、总值之间的数学对应关系问题,列式与求 aud.currentTime(当前播放时间位置)值演示如下:
aud.duration / aud.currentTime = mprog.vallue / mprog.max → aud.currentTime = mprog.value / mprog.max * aud.duration
这样,我们可以写出音频控件的 onchange 事件代码了:
mprog.onchange = () => aud.currentTime = aud.currentTime = mprog.value / mprog.max * add.duration;
至此,可以整合一~四节的代码了,下面的代码已将css代码进行了压缩,同时audio控件加入了自动播放、循环播放属性:
<style> #mplayer { position: absolute; text-align: center; color: white; } #mplayer p { margin: 0; padding: 0; } #mprog { width: 240px; accent-color: darkgreen; outline: none; cursor: pointer; } #btnplay { width: 80px; height: 80px; cursor: pointer; animation: rotating 6s infinite linear var(--state); } @keyframes rotating { to { transform: rotate(360deg); } } </style> <audio id="aud" src="https://music.163.com/song/media/outer/url?id=2113720220" autoplay loop></audio> <div id="mplayer"> <p><img id="btnplay" src="https://638183.freep.cn/638183/small/002_133507167677724892.png" title="播放/暂停" alt="" /></p> <p><input id="mprog" type="range" min="0" max="100" step="0.1" value="0" title="调节进度" /></p> </div> <script> var mseek = false; var mState = () => btnplay.style.setProperty('--state', aud.paused ? 'paused' : 'running'); aud.addEventListener('timeupdate', () => { if (!mseek) mprog.value = aud.currentTime / aud.duration * mprog.max; }); aud.addEventListener('pause', () => mState()); aud.addEventListener('playing', () => mState()); mprog.onmousedown = () => mseek = true; mprog.onmouseup = () => mseek = false; mprog.onchange = () => aud.currentTime = aud.currentTime = mprog.value / mprog.max * aud.duration; btnplay.onclick = () => aud.paused ? aud.play() : aud.pause(); </script>
上述代码已经实现了手工调整音频播放进度的功能,不论音乐在播放中还是在暂停中,我们的range进度条播放器更接近完美了。可以在 pencil code 运行上述代码或将代码存为本地html文档后运行。啰嗦一下,调节播放进度存在两种情形:音乐播放时和音乐暂停时,大家可以体验一下。
评论列表 [2条]
#2 | 飞飞 于 2024-1-30 20:35 发布: aud.currentTime = mprog.value / mprog.max * aud.duration mprog.value = aud.currentTime / aud.duration * mprog.max 小白把这两句对比起来看,更清楚些。。。
#1 | 小希 于 2024-1-29 10:03 发布: 我们的range进度条播放器更接近完美了。。。。为完美干杯。。