首页 > 解决方案 > 如何在没有 JavaScript 严格限制的情况下播放音频?

问题描述

我正在制作一个由纯 JavaScript 代码组成的游戏,我想在 JavaScript 中操作音频。具体来说,我想让页面在单击某些div元素时以及在 JavaScript 代码中使用某些函数时开始播放音乐。

我知道 HTML5 的音频标签有一个限制,即如果Audio没有用户单击音频元素的播放按钮,就无法播放与元素关联的音乐文件,所以我不能这样做:

const audio = document.createElement("audio");
audio.src = "url of source";
audio.play(); 
//Uncaught (in promise) DOMException: play() failed because 
//the user didn't interact with the document first. 
//https://developers.google.com/web/updates/2017/09/autoplay-policy-changes

Chrome 的自动播放策略很简单:

始终允许静音自动播放。在以下情况下允许自动播放声音: 用户与域进行了交互(单击、点击等)。在桌面上,用户的媒体参与指数阈值已被超过,这意味着用户之前播放过有声视频。用户已将网站添加到移动设备的主屏幕或在桌面设备上安装 PWA。顶级框架可以将自动播放权限委托给其 iframe 以允许自动播放声音。

但我想更自由地管理音频,以制作好的游戏 UI。

为了实现我的目标,我认为我需要在 JavaScript 代码中引入另一个库或 API,或者仍然使用带有一些棘手提示的音频标签。

我在想其中一个选择可能是Web Audio API

你能告诉我一些建议吗?

进步

我尝试了如下代码,当我使用 click 事件处理程序单击 div 元素时,它起作用了:

<div id="my-div">play</div>

<audio id="myAudio">
<source src="url of source" type="audio/mpeg">
</audio>
const myAudio = document.getElementById("myAudio");
const btn = document.getElementById("my-div");
btn.addEventListener("click",() => {
  myAudio.play();
});

但是,当我像下面这样写时,即使我似乎没有违反自动播放策略,它也不会出现相同的错误:

document.getElementById('my-div').addEventListener('click', () => {
    const audio = new Audio('url of source');
    audio.play();
});
//Uncaught (in promise) DOMException: play() failed because 
//the user didn't interact with the document first. 
//https://developers.google.com/web/updates/2017/09/autoplay-policy-changes

上面两个代码的主要区别是我是把音频源文件的url写在audio标签里还是写在audio标签里面的source标签里。我猜这会有所不同,但我不明白到底是什么问题。

标签: javascripthtmlaudiohtml5-audioweb-audio-api

解决方案


你是对的。只有在响应用户手势开始播放时,您才能确保播放不会被自动播放策略阻止。带有单击处理程序的按钮是经典示例,但单击处理程序也可以附加到 div。假设您的 div 有一个名为my-div. 在这种情况下,以下应该工作。

document.getElementById('my-div').addEventListener('click', () => {
    const audio = new Audio('url of source');

    audio.play(); 
});

使用 Web Audio API 不会更改自动播放策略。无论使用哪种浏览器 API,通常都适用相同的规则。


推荐阅读