请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 马黑黑 于 2024-2-26 21:28 编辑
不久前我们在音频播放器系列开发教程里接触过有关audio音频控件的自动播放问题,我们使用autoplay 属性 + audioElement.paused来解决问题,事实证明这是可行的:audioElement.paused能让我们获得audio控件是否处于暂停状态,再通过对audio控件的其它几个事件进行监听,从而构造出几近完美的音频与音画的动态联动。autoplay的缺陷是,它常会被浏览器的限制策略所阻止,且不会报错,浏览器在控制台一般也不会有提示(个别浏览器可能产生非错误级别的友好提示)。autoplay与限制策略间的此等关系对页面设计者而言多少是一种尴尬,所以,应该设计另外一种监听机制,以帮助设计者了解更多的audio控件在开始运行时的状况。
其实,除了依据paused状态,确实还存在另外的应对限制策略的机制,那就是Promise API,一个现代浏览器普遍支持的基于限制策略的接口。与对待 autoplay 属性不同,现代浏览器在audio控件首次发起播放即audioElement.play()动作的时候会触发Promise对此动作做出策略响应,且能返回错误代码,我们还可以从中获取到错误的名称——浏览器禁止自动播放时该错误名称为NotAllowedError。依此Promise机制,我们可以获知浏览器允许或禁止自动播放,进而做相应处理。
以下代码,我们不考虑旧浏览器对Promise是否支持,仅针对现代浏览器:
<div id="mydiv">
<!-- audio不设置autoplay -->
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=408532724" loop></audio>
</div>
<script>
let autoplayPromise = aud.play(); // 命令audio播放并获取Promise对象
autoplayPromise.then(() => {
console.log('ok'); //正常播放, 打印ok
//俘获错误
}).catch(err => {
console.log(err.name); // → NotAllowedError
aud.controls = true; //令audio界面显示出来让用户手动操作
});
//移除audio界面
aud.onmouseout = () => aud.controls = false;
</script>
上述代码,我们使用链式方法处理 autoplayPromise 对象实例(autoplayPromise是我们自定义的变量名),该对象如前已述,它是一个 Promise 实例,因为 audioElement.play 会返回一个 Promise 对象副本。autoplayPromise.then 意为,如若 autoplayPromise 正常,那么(then就是那么的意思),做点什么,示例中是在控制台打印OK,然后 .catch 是俘获错误信息,我们打印出错误的名称,接着呈现audio界面。最后,用户不论手动播放音频与否,鼠标指针从播放器界面上移开后,我们让播放器界面消失。这个示例仅是演示,若使用于生产环境,需要做一些额外工作,以提升页面与用户交互的友好性。
有意思的是,在本帖运行示例代码,播放器都能成功播放,不论浏览器限制策略是否禁止自动播放。这是为什么呢?原因很简单,我们点击了“运行代码”按钮才去运行 aud.play(),浏览器就认为这是用户与页面已经做了交互、是用户许可播放音频的,aud.play 触发的 Promise 限制策略故此放行。若示例代码单独保存为一个HTML文档,情形则不一样:如果不允许自动播放,则 Promise 不会放行,演示的代码就会显示出audio界面;反之则自动播放音乐。
更有意思的是,当audio控件处于静音状态(muted)或音量为0(volume=0)时,限制策略也会放行audio的音频自动播放,一些实现音频自动播放的方法基于此特性,然后会引导用户解除静音状态或调解音量。这方法有点另类,且不是十分牢靠:严格机制下的限制策略,静音与音量为零是音频一样不可以自动播放,一切依赖于当前浏览器的限制级别与用户对浏览器的相关设置。所以还是不要痴心妄想,老老实实采取理性的做法:允许自动播放就自动播放,不允许就将选择权交给用户。
|