Promise处理音频自动播放实例
本帖最后由 马黑黑 于 2024-2-26 18:27 编辑 <br /><br /><h2>效果:</h2><style>
#mydiv {
margin: 20px auto;
width: 720px;
height: 360px;
border: 1px solid gray;
position: relative;
}
#player {
position: absolute;
right: 20px;
top: 20px;
cursor: pointer;
animation: rot 5s linear infinite var(--state);
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>
<div id="mydiv">
<audio id="aud" src="http://www.kumeiwp.com/sub/filestores/2023/12/13/8bbd28a68e37df522563ce652bf0bae6.mp3"></audio>
<img id="player" src="https://638183.freep.cn/638183/small/hxxb.png" alt="" />
</div>
<h2>代码:</h2>
<style>
.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>
<div class='mum'>
<cl-cd data-idx="1"><style></cl-cd>
<cl-cd data-idx="2">#mydiv {</cl-cd>
<cl-cd data-idx="3"> <span class="tBlue">margin:</span> 20px auto;</cl-cd>
<cl-cd data-idx="4"> <span class="tBlue">width:</span> 720px;</cl-cd>
<cl-cd data-idx="5"> <span class="tBlue">height:</span> 360px;</cl-cd>
<cl-cd data-idx="6"> <span class="tBlue">border:</span> 1px solid gray;</cl-cd>
<cl-cd data-idx="7"> <span class="tBlue">position:</span> relative;</cl-cd>
<cl-cd data-idx="8">}</cl-cd>
<cl-cd data-idx="9">#player {</cl-cd>
<cl-cd data-idx="10"> <span class="tBlue">position:</span> absolute;</cl-cd>
<cl-cd data-idx="11"> <span class="tBlue">right:</span> 20px;</cl-cd>
<cl-cd data-idx="12"> <span class="tBlue">top:</span> 20px;</cl-cd>
<cl-cd data-idx="13"> <span class="tBlue">cursor:</span> pointer;</cl-cd>
<cl-cd data-idx="14"> <span class="tBlue">animation:</span> rot 5s linear infinite <span class="tBlue">var</span>(--state);</cl-cd>
<cl-cd data-idx="15">}</cl-cd>
<cl-cd data-idx="16">@keyframes rot { to { <span class="tBlue">transform:</span> rotate(360deg); } }</cl-cd>
<cl-cd data-idx="17"></style></cl-cd>
<cl-cd data-idx="18"><br></cl-cd>
<cl-cd data-idx="19"><div <span class="tRed">id</span>=<span class="tMagenta">"mydiv"</span>></cl-cd>
<cl-cd data-idx="20"> <audio <span class="tRed">id</span>=<span class="tMagenta">"aud"</span> src=<span class="tMagenta">"http://www.kumeiwp.com/sub/filestores/2023/12/13/8bbd28a68e37df522563ce652bf0bae6.mp3"</span>></audio></cl-cd>
<cl-cd data-idx="21"> <img <span class="tRed">id</span>=<span class="tMagenta">"player"</span> src=<span class="tMagenta">"https://638183.freep.cn/638183/small/hxxb.png"</span> alt=<span class="tMagenta">""</span> /></cl-cd>
<cl-cd data-idx="22"></div></cl-cd>
<cl-cd data-idx="23"><br></cl-cd>
<cl-cd data-idx="24"><script></cl-cd>
<cl-cd data-idx="25"><br></cl-cd>
<cl-cd data-idx="26"><span class="tBlue">var</span> flashId; <span class="tGreen">//setTimeout定时器运行<span class="tBlue">ID:</span> 用于音频不允许自动播放时</span></cl-cd>
<cl-cd data-idx="27"><br></cl-cd>
<cl-cd data-idx="28"><span class="tGreen">//联动函数 : 与音频播放暂停同步联动 - 关键帧动画、播放器提示语</span></cl-cd>
<cl-cd data-idx="29">mState = () => {</cl-cd>
<cl-cd data-idx="30"> aud.paused</cl-cd>
<cl-cd data-idx="31"> ? (mydiv.style.setProperty(<span class="tMagenta">'--state'</span>,<span class="tMagenta">'paused'</span>), player.title = <span class="tMagenta">'点击播放'</span>)</cl-cd>
<cl-cd data-idx="32"> : (mydiv.style.setProperty(<span class="tMagenta">'--state'</span>,<span class="tMagenta">'running'</span>), player.title = <span class="tMagenta">'点击暂停'</span>)</cl-cd>
<cl-cd data-idx="33"> ;</cl-cd>
<cl-cd data-idx="34">};</cl-cd>
<cl-cd data-idx="35"><br></cl-cd>
<cl-cd data-idx="36"><span class="tGreen">//flash函数 : 音频禁止自动播放是调用 - 播放器变大变小,引导访问者点击</span></cl-cd>
<cl-cd data-idx="37">flash = () => {</cl-cd>
<cl-cd data-idx="38"> <span class="tBlue">let</span> idx = <span class="tRed">Math</span>.round(<span class="tRed">Math</span>.random());</cl-cd>
<cl-cd data-idx="39"> <span class="tBlue">let</span> val = ;</cl-cd>
<cl-cd data-idx="40"> player.style.transform = `scale(${val})`;</cl-cd>
<cl-cd data-idx="41"> <span class="tGreen">//setTimeout定时器递归调用此函数</span></cl-cd>
<cl-cd data-idx="42"> flashId = setTimeout(flash,300);</cl-cd>
<cl-cd data-idx="43">};</cl-cd>
<cl-cd data-idx="44"><br></cl-cd>
<cl-cd data-idx="45"><span class="tGreen">//aud.play事件Promise链式处理</span></cl-cd>
<cl-cd data-idx="46">aud.play().then(() => {</cl-cd>
<cl-cd data-idx="47"> mState(); <span class="tGreen">//音频正常自动播放 : 运行联动函数</span></cl-cd>
<cl-cd data-idx="48">}).<span class="tBlue">catch</span>(err => { <span class="tGreen">//俘获错误</span></cl-cd>
<cl-cd data-idx="49"> <span class="tBlue">if</span> (err.name === <span class="tMagenta">"NotAllowedError"</span>) {</cl-cd>
<cl-cd data-idx="50"> flash(); <span class="tGreen">//禁止自动播放时运行flash函数</span></cl-cd>
<cl-cd data-idx="51"> } <span class="tBlue">else</span> {</cl-cd>
<cl-cd data-idx="52"> alert(err); <span class="tGreen">//音频加载出错时显示错误信息</span></cl-cd>
<cl-cd data-idx="53"> }</cl-cd>
<cl-cd data-idx="54"> mState(); <span class="tGreen">//即便不能播放也要运行联动函数</span></cl-cd>
<cl-cd data-idx="55">});</cl-cd>
<cl-cd data-idx="56"><br></cl-cd>
<cl-cd data-idx="57"><span class="tGreen">//下面是两个audio控件监听事件</span></cl-cd>
<cl-cd data-idx="58">aud.addEventListener(<span class="tMagenta">'pause'</span>, mState);</cl-cd>
<cl-cd data-idx="59">aud.addEventListener(<span class="tMagenta">'playing'</span>, mState);</cl-cd>
<cl-cd data-idx="60"><br></cl-cd>
<cl-cd data-idx="61"><span class="tGreen">//播放按钮点击事件</span></cl-cd>
<cl-cd data-idx="62">player.onclick = () => {</cl-cd>
<cl-cd data-idx="63"> <span class="tGreen">//如果 flashID 活跃中(不能自动播放时会被赋值)</span></cl-cd>
<cl-cd data-idx="64"> <span class="tBlue">if</span>(flashId) {</cl-cd>
<cl-cd data-idx="65"> flashId = clearTimeout(flashId); <span class="tGreen">//销毁它</span></cl-cd>
<cl-cd data-idx="66"> <span class="tGreen">//复原播放器的transform 属性让道给animation)</span></cl-cd>
<cl-cd data-idx="67"> player.style.transform = <span class="tMagenta">'unset'</span>; </cl-cd>
<cl-cd data-idx="68"> }</cl-cd>
<cl-cd data-idx="69"> <span class="tGreen">//按钮自己本分活儿 : 音频播放时停放、暂停时播放</span></cl-cd>
<cl-cd data-idx="70"> aud.paused ? aud.play() : aud.pause();</cl-cd>
<cl-cd data-idx="71">}</cl-cd>
<cl-cd data-idx="72"><br></cl-cd>
<cl-cd data-idx="73"></script></cl-cd>
</div>
<script>
var flashId;
mState = () => {
aud.paused
? (mydiv.style.setProperty('--state','paused'), player.title = '点击播放')
: (mydiv.style.setProperty('--state','running'), player.title = '点击暂停')
;
};
flash = () => {
let idx = Math.round(Math.random());
let val = ;
player.style.transform = `scale(${val})`;
flashId = setTimeout(flash,300);
};
aud.play().then(() => {
mState();
}).catch(err => {
if (err.name === "NotAllowedError") {
flash();
} else {
alert(err);
}
mState();
});
aud.addEventListener('pause', mState);
aud.addEventListener('playing', mState);
player.onclick = () => {
if(flashId) {
flashId = clearTimeout(flashId);
player.style.transform = 'unset';
}
aud.paused ? aud.play() : aud.pause();
}
</script> 本帖最后由 马黑黑 于 2024-2-26 18:27 编辑
audio.play().then( () => { ... }).catch(err => { ... });
上面一行的结构,就是Promise的链式运行方式。audio.play() 会返回一个 Promise 信息,如果成功播放,则(then)做点什么,否则,俘获(catch)错误,err 是我们定义的装载错误信息的容器变量。就这么简单。
俘获错误代码块有两个分支,一个是浏览器禁止自动播放,若此,我们就让播放按钮搞点动作(flash函数),以吸引访问者的注意,从而可能去点击它;另一个是音频播放方面出现的错误,可能是音频资源有问题或是格式不对、网络太慢无法下载等等等,具体是什么由 err 变量去说吧,会是一两行英文。 占楼 不播放的时候这个小花还会放大小缩小闪烁提示。。。十分友好啊。。
播放的时候小花保持大小不变了。。
不过这次鼠标怎么划拉小花都在。{:4_173:} 也就是说,无论是否设置了音频自动播放,都油路可走了呢{:4_199:} 设置不允许自动播放会得到提示,如果可以播放,那就一切太平{:4_173:} 无论成功还是失败,都能有个说法,这样真好{:4_187:} 醉美水芙蓉 发表于 2024-2-26 18:24
黑黑老师晚上好!老师制作辛苦了!
{:4_190:} 红影 发表于 2024-2-26 18:59
无论成功还是失败,都能有个说法,这样真好
我们之前用的实现方法其实也挺好,唯一没做的只是一个出错检测机制,可以酱紫:
aud.onerror = () => 做点什么; 红影 发表于 2024-2-26 18:50
设置不允许自动播放会得到提示,如果可以播放,那就一切太平
你要知道,大多数权限是有浏览器的使用者设置的,而绝大多数人不会去设置浏览器,所以,专业的播放机制应该考虑到。 红影 发表于 2024-2-26 18:48
也就是说,无论是否设置了音频自动播放,都油路可走了呢
油有木有去问问 @梦油 先生,盐我知道木有{:4_170:} 南无月 发表于 2024-2-26 18:28
不播放的时候这个小花还会放大小缩小闪烁提示。。。十分友好啊。。
播放的时候小花保持大小不变了。。
这叫花常在 马黑黑 发表于 2024-2-26 19:32
我们之前用的实现方法其实也挺好,唯一没做的只是一个出错检测机制,可以酱紫:
aud.onerror = () =>...
嗯嗯,这样就更完美了{:4_187:} 红影 发表于 2024-2-26 19:37
嗯嗯,这样就更完美了
我有个别帖子会用到 马黑黑 发表于 2024-2-26 19:34
你要知道,大多数权限是有浏览器的使用者设置的,而绝大多数人不会去设置浏览器,所以,专业的播放机制应 ...
黑黑说得太对了,以前我就不懂设置,新到手的电脑通常没法自动播放呢{:4_173:} 马黑黑 发表于 2024-2-26 19:34
油有木有去问问 @梦油 先生,盐我知道木有
有路可走,不是油路,打错字了{:4_170:} 红影 发表于 2024-2-26 19:39
黑黑说得太对了,以前我就不懂设置,新到手的电脑通常没法自动播放呢
不过设置不是个问题 红影 发表于 2024-2-26 19:40
有路可走,不是油路,打错字了
油路其实也挺好,走得快 马黑黑 发表于 2024-2-26 19:41
油路其实也挺好,走得快
不用走,直接滑就行了呗{:4_170:}