马黑黑 发表于 2024-2-26 18:15

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">&lt;style&gt;</cl-cd>
<cl-cd data-idx="2">#mydiv {</cl-cd>
<cl-cd data-idx="3">&nbsp; &nbsp; <span class="tBlue">margin:</span> 20px auto;</cl-cd>
<cl-cd data-idx="4">&nbsp; &nbsp; <span class="tBlue">width:</span> 720px;</cl-cd>
<cl-cd data-idx="5">&nbsp; &nbsp; <span class="tBlue">height:</span> 360px;</cl-cd>
<cl-cd data-idx="6">&nbsp; &nbsp; <span class="tBlue">border:</span> 1px solid gray;</cl-cd>
<cl-cd data-idx="7">&nbsp; &nbsp; <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">&nbsp; &nbsp; <span class="tBlue">position:</span> absolute;</cl-cd>
<cl-cd data-idx="11">&nbsp; &nbsp; <span class="tBlue">right:</span> 20px;</cl-cd>
<cl-cd data-idx="12">&nbsp; &nbsp; <span class="tBlue">top:</span> 20px;</cl-cd>
<cl-cd data-idx="13">&nbsp; &nbsp; <span class="tBlue">cursor:</span> pointer;</cl-cd>
<cl-cd data-idx="14">&nbsp; &nbsp; <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">&lt;/style&gt;</cl-cd>
<cl-cd data-idx="18"><br></cl-cd>
<cl-cd data-idx="19">&lt;div <span class="tRed">id</span>=<span class="tMagenta">"mydiv"</span>&gt;</cl-cd>
<cl-cd data-idx="20">&nbsp; &nbsp; &lt;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>&gt;&lt;/audio&gt;</cl-cd>
<cl-cd data-idx="21">&nbsp; &nbsp; &lt;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> /&gt;</cl-cd>
<cl-cd data-idx="22">&lt;/div&gt;</cl-cd>
<cl-cd data-idx="23"><br></cl-cd>
<cl-cd data-idx="24">&lt;script&gt;</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 = () =&gt; {</cl-cd>
<cl-cd data-idx="30">&nbsp; &nbsp; aud.paused</cl-cd>
<cl-cd data-idx="31">&nbsp; &nbsp; &nbsp; &nbsp; ? (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">&nbsp; &nbsp; &nbsp; &nbsp; : (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">&nbsp; &nbsp; ;</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 = () =&gt; {</cl-cd>
<cl-cd data-idx="38">&nbsp; &nbsp; <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">&nbsp; &nbsp; <span class="tBlue">let</span> val = ;</cl-cd>
<cl-cd data-idx="40">&nbsp; &nbsp; player.style.transform = `scale(${val})`;</cl-cd>
<cl-cd data-idx="41">&nbsp; &nbsp; <span class="tGreen">//setTimeout定时器递归调用此函数</span></cl-cd>
<cl-cd data-idx="42">&nbsp; &nbsp; 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(() =&gt; {</cl-cd>
<cl-cd data-idx="47">&nbsp; &nbsp; mState(); <span class="tGreen">//音频正常自动播放 : 运行联动函数</span></cl-cd>
<cl-cd data-idx="48">}).<span class="tBlue">catch</span>(err =&gt; { <span class="tGreen">//俘获错误</span></cl-cd>
<cl-cd data-idx="49">&nbsp; &nbsp; <span class="tBlue">if</span> (err.name === <span class="tMagenta">"NotAllowedError"</span>) {</cl-cd>
<cl-cd data-idx="50">&nbsp; &nbsp; &nbsp; &nbsp; flash(); <span class="tGreen">//禁止自动播放时运行flash函数</span></cl-cd>
<cl-cd data-idx="51">&nbsp; &nbsp; } <span class="tBlue">else</span> {</cl-cd>
<cl-cd data-idx="52">&nbsp; &nbsp; &nbsp; &nbsp; alert(err); <span class="tGreen">//音频加载出错时显示错误信息</span></cl-cd>
<cl-cd data-idx="53">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="54">&nbsp; &nbsp; 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 = () =&gt; {</cl-cd>
<cl-cd data-idx="63">&nbsp; &nbsp; <span class="tGreen">//如果 flashID 活跃中(不能自动播放时会被赋值)</span></cl-cd>
<cl-cd data-idx="64">&nbsp; &nbsp; <span class="tBlue">if</span>(flashId) {</cl-cd>
<cl-cd data-idx="65">&nbsp; &nbsp; &nbsp; &nbsp; flashId = clearTimeout(flashId); <span class="tGreen">//销毁它</span></cl-cd>
<cl-cd data-idx="66">&nbsp; &nbsp; &nbsp; &nbsp; <span class="tGreen">//复原播放器的transform 属性让道给animation)</span></cl-cd>
<cl-cd data-idx="67">&nbsp; &nbsp; &nbsp; &nbsp; player.style.transform = <span class="tMagenta">'unset'</span>; </cl-cd>
<cl-cd data-idx="68">&nbsp; &nbsp; }</cl-cd>
<cl-cd data-idx="69">&nbsp; &nbsp; <span class="tGreen">//按钮自己本分活儿 : 音频播放时停放、暂停时播放</span></cl-cd>
<cl-cd data-idx="70">&nbsp; &nbsp; 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">&lt;/script&gt;</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:24

马黑黑 发表于 2024-2-26 18:24

本帖最后由 马黑黑 于 2024-2-26 18:27 编辑

audio.play().then( () => { ... }).catch(err => { ... });

上面一行的结构,就是Promise的链式运行方式。audio.play() 会返回一个 Promise 信息,如果成功播放,则(then)做点什么,否则,俘获(catch)错误,err 是我们定义的装载错误信息的容器变量。就这么简单。

俘获错误代码块有两个分支,一个是浏览器禁止自动播放,若此,我们就让播放按钮搞点动作(flash函数),以吸引访问者的注意,从而可能去点击它;另一个是音频播放方面出现的错误,可能是音频资源有问题或是格式不对、网络太慢无法下载等等等,具体是什么由 err 变量去说吧,会是一两行英文。

南无月 发表于 2024-2-26 18:26

占楼

南无月 发表于 2024-2-26 18:28

不播放的时候这个小花还会放大小缩小闪烁提示。。。十分友好啊。。
播放的时候小花保持大小不变了。。

不过这次鼠标怎么划拉小花都在。{:4_173:}

红影 发表于 2024-2-26 18:48

也就是说,无论是否设置了音频自动播放,都油路可走了呢{:4_199:}

红影 发表于 2024-2-26 18:50

设置不允许自动播放会得到提示,如果可以播放,那就一切太平{:4_173:}

红影 发表于 2024-2-26 18:59

无论成功还是失败,都能有个说法,这样真好{:4_187:}

马黑黑 发表于 2024-2-26 19:30

醉美水芙蓉 发表于 2024-2-26 18:24
黑黑老师晚上好!老师制作辛苦了!

{:4_190:}

马黑黑 发表于 2024-2-26 19:32

红影 发表于 2024-2-26 18:59
无论成功还是失败,都能有个说法,这样真好

我们之前用的实现方法其实也挺好,唯一没做的只是一个出错检测机制,可以酱紫:

aud.onerror = () => 做点什么;

马黑黑 发表于 2024-2-26 19:34

红影 发表于 2024-2-26 18:50
设置不允许自动播放会得到提示,如果可以播放,那就一切太平

你要知道,大多数权限是有浏览器的使用者设置的,而绝大多数人不会去设置浏览器,所以,专业的播放机制应该考虑到。

马黑黑 发表于 2024-2-26 19:34

红影 发表于 2024-2-26 18:48
也就是说,无论是否设置了音频自动播放,都油路可走了呢
油有木有去问问 @梦油 先生,盐我知道木有{:4_170:}

马黑黑 发表于 2024-2-26 19:35

南无月 发表于 2024-2-26 18:28
不播放的时候这个小花还会放大小缩小闪烁提示。。。十分友好啊。。
播放的时候小花保持大小不变了。。



这叫花常在

红影 发表于 2024-2-26 19:37

马黑黑 发表于 2024-2-26 19:32
我们之前用的实现方法其实也挺好,唯一没做的只是一个出错检测机制,可以酱紫:

aud.onerror = () =>...

嗯嗯,这样就更完美了{:4_187:}

马黑黑 发表于 2024-2-26 19:39

红影 发表于 2024-2-26 19:37
嗯嗯,这样就更完美了

我有个别帖子会用到

红影 发表于 2024-2-26 19:39

马黑黑 发表于 2024-2-26 19:34
你要知道,大多数权限是有浏览器的使用者设置的,而绝大多数人不会去设置浏览器,所以,专业的播放机制应 ...

黑黑说得太对了,以前我就不懂设置,新到手的电脑通常没法自动播放呢{:4_173:}

红影 发表于 2024-2-26 19:40

马黑黑 发表于 2024-2-26 19:34
油有木有去问问 @梦油 先生,盐我知道木有

有路可走,不是油路,打错字了{:4_170:}

马黑黑 发表于 2024-2-26 19:40

红影 发表于 2024-2-26 19:39
黑黑说得太对了,以前我就不懂设置,新到手的电脑通常没法自动播放呢

不过设置不是个问题

马黑黑 发表于 2024-2-26 19:41

红影 发表于 2024-2-26 19:40
有路可走,不是油路,打错字了

油路其实也挺好,走得快

红影 发表于 2024-2-26 19:42

马黑黑 发表于 2024-2-26 19:41
油路其实也挺好,走得快

不用走,直接滑就行了呗{:4_170:}
页: [1] 2 3 4 5 6 7 8 9
查看完整版本: Promise处理音频自动播放实例