马黑黑 发表于 2024-1-29 07:56

保姆级range进度条音频播放器开发教程(四)

<style>
.mum { font-size: 18px; }
.mum pre { padding: 12px; background: #eee; color: blue; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; tab-size: 4; white-space: pre-wrap; word-wrap: break-word; }
.mum a { color: darkred; }
.mum a:hover { color: red; }
.tGreen { color: green; }
.tRed { color: red; }
</style>

<div class="mum">

<p>到第三节 <a href="https://www.huachaowang.com/forum.php?mod=viewthread&tid=73878&extra=page%3D1" target="_blank">保姆级range进度条音频播放器开发教程(三)</a> 的时候,我们的range进度条播放器不仅有模有样,还与音乐的播放/暂停智能联动,算是成功的作品了。下一步,我们想让 range 滑杆发挥更大的作用,即可以通过拖曳滑杆的滑块改变音频的播放位置,而不仅仅是显示音乐的播放进度。这将是本节的核心内容。</p>
<p>range滑块自身是可以随意拖动的,不过,它现在由 audio 的 timeupdate 监听事件控制着,在音乐播放的时候,拖曳滑块并不管用,timeupdate 监听事件总是会将其复位到音频的当前播放位置。我们得设计一个机制,以实现如下功能:当用户想要改变播放位置时,我们让 timeupdate 监听事件暂停工作,把滑杆滑块的滑动权交出来,待用户改变音乐的播放位置操作结束了再将滑动权还给它。</p>
<p>这需要引入一个布尔变量,我们用 mseek 来命名,m 还是music,seek 本意查找,这里指用户查找新的播放位置(mseek只是一个命名,可以随意)。当 mseek 为真(true),表明用户要进行进度调节操作,timeupdate 监听事件就先不驱动 range 的运行,待用户操作完毕,即当 mseek 为假(false)之时,timeupdate 监听机制继续工作。看看怎么声明 mseek 变量:</p>
<pre>
var mseek = false;
</pre>
<p>var 是 JS 声明变量的关键词,除它以外,还有 let,const,它们的区别先不用理睬,我们就用 var 好了。var 之后紧接着一个自定义变量名称(彼此间有空格),然后用等号给它一个值,布尔变量非真即假,真表示为 true,假表示为 false,我们上面给 mseek 的赋值是 false,这又为什么呢?因为,开始的时候,用户没有去操作进度调整,这时呢,timeupdate 监听机制要驱动 range 的进度运行。对应地,audio 的 timeupdate 监听事件我们要给它添加一个条件语句:</p>
<pre>
var mseek = false;

aud.addEventListener('timeupdate', () => {
        <span class="tRed">if (!mseek)</span> mprog.value = aud.currentTime / aud.duration * mprog.max;
});
</pre>
<p>注意红色代码,它就是条件语句,if (!mseek) 相当于 if (mseek !== true)、等同于 if (mseek === false) ,就是如果 mseek 变量不为真之意,具体来说是,如果用户没有手动调节进度之时。感叹号 <span class="tRed">!</span> 在这里表示 mseek 的否定,三个等号表示绝对等于,感叹号加两个等号表示绝对不等于,这都太复杂,所以我们用 <span class="tRed">!mseek</span> 来表示不为真即不等于真。if (!mseek) 语句加持后,timeupdate监听事件就更加聪明了,它指挥进度条的权限完全依赖于 mseek 变量值的变化:为假时驱动进度条的运行,为真时是用户正在手动调节进度,就不瞎掺和来着。这样,我们下一步要做的就是,如何获知用户正在调节进度了。</p>
<p>用户调节播放进度,需要在 range 滑块上按下鼠标左键,JS对此有个对应的处理事件,叫 onmousedown,意思是鼠标左键按下之时,可用于任意可视元素。页面上鼠标按下的动作频繁,我们只需针对 input 的 range 控件,它的 id 为 mprog,在它上面按下鼠标左键时:</p>
<pre>
mprog.onmousedown = () => mseek = true;
</pre>
<p>意思是,mprog 元素之上,当鼠标左键按下时,执行 mseek = true 语句,就是,令 mseek 布尔变量值为真。mseek 为真,timeupdate 监听事件就不再驱动 mprog 的运行,用户就可以随意拖动滑杆上的滑块了。</p>
<p>用户调节完毕,mseek 的值还需要变回假,以便进度条能够显示当前正确的播放位置。这得用到JS的鼠标松开事件,onmouseup,同样地,我们只管 mprog 的鼠标松开事件:</p>
<pre>
mprog.onmouseup = () => mseek = false;
</pre>
<p>鼠标键松开时就是需要改变音乐播放位置的时候,这又用到 input type="range" 元素即滑杆的 onchange 或 oninput 事件,这两个事件都表示滑杆 value 值改变之时,我们选用 onchange 事件(其实用哪个都行),它在鼠标左键或键盘方向键松开之时触发,代码如下:</p>
<pre>
mprog.onchange = () => <span class="tGreen">/* 做点什么 */<span>;
</pre>
<p>“做点什么”又是一个要处理的一个问题,这只是数学问题,它还是 aud.duration、aud.currentTime、mprog.vallue、mprog.max 即音频控件总时长、当前播放时间和滑杆当前值、总值之间的数学对应关系问题,列式与求 aud.currentTime(当前播放时间位置)值演示如下:</p>
<pre>
aud.duration / <span class="tRed">aud.currentTime</span> = mprog.vallue / mprog.max →
<span class="tRed">aud.currentTime</span> = mprog.value / mprog.max * aud.duration
</pre>
<p>这样,我们可以写出音频控件的 onchange 事件代码了:</p>
<pre>
mprog.onchange = () => aud.currentTime = aud.currentTime = mprog.value / mprog.max * add.duration;
</pre>
<p>至此,可以整合一~四节的代码了,下面的代码已将css代码进行了压缩,同时audio控件加入了自动播放、循环播放属性:</p>
<pre>
&lt;style&gt;
#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); } }
&lt;/style&gt;

&lt;audio id="aud" src="https://music.163.com/song/media/outer/url?id=2113720220" <span class="tRed">autoplay loop</span>&gt;&lt;/audio&gt;
&lt;div id="mplayer"&gt;
        &lt;p&gt;&lt;img id="btnplay" src="https://638183.freep.cn/638183/small/002_133507167677724892.png" title="播放/暂停" alt="" /&gt;&lt;/p&gt;
        &lt;p&gt;&lt;input id="mprog" type="range" min="0" max="100" step="0.1" value="0" title="调节进度" /&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;script&gt;

<span class="tRed">var mseek = false;</span>

var mState = () =&gt; btnplay.style.setProperty('--state', aud.paused ? 'paused' : 'running');

aud.addEventListener('timeupdate', () =&gt; {
        <span class="tRed">if (!mseek)</span> mprog.value = aud.currentTime / aud.duration * mprog.max;
});
aud.addEventListener('pause', () =&gt; mState());
aud.addEventListener('playing', () =&gt; mState());
<span class="tRed">
mprog.onmousedown = () => mseek = true;
mprog.onmouseup = () => mseek = false;
mprog.onchange = () => aud.currentTime = aud.currentTime = mprog.value / mprog.max * aud.duration;
</span>
btnplay.onclick = () =&gt; aud.paused ? aud.play() : aud.pause();

&lt;/script&gt;
</pre>
<p>上述代码已经实现了手工调整音频播放进度的功能,不论音乐在播放中还是在暂停中,我们的range进度条播放器更接近完美了。可以在 <a href="http://mhh.52qingyin.cn/api/pcode/" target="_blank">pencil code</a>
运行上述代码或将代码存为本地html文档后运行。啰嗦一下,调节播放进度存在两种情形:音乐播放时和音乐暂停时,大家可以体验一下。</p>

</div>

红影 发表于 2024-1-29 09:46

记得这个感叹号的功能黑黑之前讲解过的,这个帖子里再复习一遍,可以更清楚了{:4_187:}

红影 发表于 2024-1-29 09:52

之前的课程讲述了滑杆和音乐进度的关联,这节讲了同样有关联且怎样让滑杆接收手动控制。
为方便记忆,可以简单地这样理解,纯关联是音乐的当前值除以总值的比值,得到滑杆总值上的位置。手动关联是滑杆的当前值和总值的比值,得到在音乐总值上的位置。

红影 发表于 2024-1-29 09:52

这个还和鼠标的动作关联,很智能的判断{:4_204:}

马黑黑 发表于 2024-1-29 17:04

红影 发表于 2024-1-29 09:52
这个还和鼠标的动作关联,很智能的判断

JS有不少鼠标操作的函数和方法

马黑黑 发表于 2024-1-29 17:05

红影 发表于 2024-1-29 09:46
记得这个感叹号的功能黑黑之前讲解过的,这个帖子里再复习一遍,可以更清楚了

JS里的感叹号别的用途还有,这里就不节外生枝了

马黑黑 发表于 2024-1-29 17:07

红影 发表于 2024-1-29 09:52
之前的课程讲述了滑杆和音乐进度的关联,这节讲了同样有关联且怎样让滑杆接收手动控制。
为方便记忆,可以 ...

数学问题很重要,讲到这里就能体现出来了。虽然这是简单的数学问题,不理解的话,这里就会卡壳了,谈何开发?

红影 发表于 2024-1-29 20:11

马黑黑 发表于 2024-1-29 17:04
JS有不少鼠标操作的函数和方法

这个需要一点点学习了{:4_187:}

红影 发表于 2024-1-29 20:11

马黑黑 发表于 2024-1-29 17:05
JS里的感叹号别的用途还有,这里就不节外生枝了

嗯嗯,这样好,讲多多反倒记不住。

红影 发表于 2024-1-29 20:12

马黑黑 发表于 2024-1-29 17:07
数学问题很重要,讲到这里就能体现出来了。虽然这是简单的数学问题,不理解的话,这里就会卡壳了,谈何开 ...

就是一个简单的比例,也能牵涉到数学啊{:4_173:}

马黑黑 发表于 2024-1-29 20:14

红影 发表于 2024-1-29 20:12
就是一个简单的比例,也能牵涉到数学啊

难道比例不是数学问题?

马黑黑 发表于 2024-1-29 20:14

红影 发表于 2024-1-29 20:11
嗯嗯,这样好,讲多多反倒记不住。

是的

马黑黑 发表于 2024-1-29 20:14

红影 发表于 2024-1-29 20:11
这个需要一点点学习了

鼠标的事件也不多的

红影 发表于 2024-1-30 13:54

马黑黑 发表于 2024-1-29 20:14
难道比例不是数学问题?

数学的范畴要大得多了啊{:4_173:}

红影 发表于 2024-1-30 13:54

马黑黑 发表于 2024-1-29 20:14
是的

一次能记住一个就很好了呢{:4_204:}

红影 发表于 2024-1-30 13:55

马黑黑 发表于 2024-1-29 20:14
鼠标的事件也不多的

它就接触或点击,也干不了别的{:4_173:}

马黑黑 发表于 2024-1-30 17:58

红影 发表于 2024-1-30 13:55
它就接触或点击,也干不了别的

反正鼠标事件可以数的出来

马黑黑 发表于 2024-1-30 17:58

红影 发表于 2024-1-30 13:54
一次能记住一个就很好了呢

{:4_190:}

红影 发表于 2024-1-30 22:02

马黑黑 发表于 2024-1-30 17:58
反正鼠标事件可以数的出来

以后鼠标会被触屏代替,能干的就多了。

红影 发表于 2024-1-30 22:03

马黑黑 发表于 2024-1-30 17:58


谢茶{:4_187:}
页: [1] 2 3
查看完整版本: 保姆级range进度条音频播放器开发教程(四)