提问人:Steven 提问时间:4/20/2018 更新时间:7/2/2023 访问量:520749
如何处理 Chrome 66 桌面上的“Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document”?
How to handle "Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first." on Desktop with Chrome 66?
问:
我收到错误消息。.
未捕获(承诺中) DOMException:play() 失败,因为用户没有先与文档交互。
..尝试使用 Chrome 版本 66 在桌面上播放视频时。
我确实发现了一个广告,该广告使用以下 HTML 在网站上自动开始播放:
<video
title="Advertisement"
webkit-playsinline="true"
playsinline="true"
style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
src="http://ds.serving-sys.com/BurstingRes/Site-2500/Type-16/1ff26f6a-aa27-4b30-a264-df2173c79623.mp4"
autoplay=""></video>
那么,绕过 Chrome v66 的自动播放阻止程序真的像向元素添加 、 和 属性一样简单吗?这有什么负面影响吗?webkit-playsinline="true"
playsinline="true"
autoplay=""
<video>
答:
回答手头的问题...
不,仅仅拥有这些属性是不够的,为了能够自动播放带有音频的媒体,您需要在文档上注册用户手势。
但是,这个限制非常薄弱:如果你确实在父文档上收到了这个用户手势,并且你的视频是从iframe加载的,那么你可以播放它......
所以以这把小提琴为例,它只是
<video src="myvidwithsound.webm" autoplay=""></video>
在第一次加载时,如果你不点击任何位置,它就不会运行,因为我们还没有注册任何事件。
但是,一旦单击“运行”按钮,父文档(jsfiddle.net)确实收到了用户手势,现在视频可以播放,即使它在技术上加载到不同的文档中。
但是,由于以下代码片段需要您实际单击“运行代码片段”按钮,因此将自动播放。
<video src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" autoplay=""></video>
这意味着您的广告之所以能够播放,可能是因为您确实向主页提供了用户手势。
现在,请注意,Safari 和 Mobile Chrome 的规则比这更严格,并且要求您至少以编程方式在用户事件处理程序本身的 or 元素上实际触发一次该方法。play()
<video>
<audio>
btn.onclick = e => {
// mark our MediaElement as user-approved
vid.play().then(()=>vid.pause());
// now we can do whatever we want at any time with this MediaElement
setTimeout(()=> vid.play(), 3000);
};
<button id="btn">play in 3s</button>
<video
src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" id="vid"></video>
如果你不需要音频,那么就不要把它附加到你的媒体上,只有视频轨道的视频也可以自动播放,这将减少用户的带宽使用。
评论
.play
.pause
vid.play.then(vid.pause.bind(vid))
vid.play.then(()=>vid.pause())
在地址栏中键入 Chrome://flags
搜索:自动播放
自动播放策略
决定是否允许音频或视频时使用的策略 自动播放。
– Mac、Windows、Linux、Chrome OS、Android
将此设置为“不需要用户手势”"
重新启动 Chrome,您无需更改任何代码
评论
- 打开
chrome://settings/content/sound
- 设置 不需要用户手势
- 重新启动 Chrome
评论
--autoplay-policy=no-user-gesture-required
要使 html 5 元素上的自动播放在 chrome 66 更新后工作,您只需将属性添加到视频元素即可。muted
所以你当前的视频HTML
<video
title="Advertisement"
webkit-playsinline="true"
playsinline="true"
style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
autoplay=""></video>
只是需要muted="muted"
<video
title="Advertisement"
style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
autoplay="true"
muted="muted"></video>
我相信 chrome 66 更新正试图阻止标签在用户标签上产生随机噪音。这就是 muted 属性使自动播放再次工作的原因。
评论
mute
volume
muted="true"
muted=true
muted=false
muted
我发现的最好的解决方案是将视频静音
[HTML全文]
<video loop muted autoplay id="videomain">
<source src="videoname.mp4" type="video/mp4">
</video>
我在 Android 手机上玩时遇到了一些问题。 经过几次尝试,我发现当流量节省程序打开时,没有自动播放:
如果启用了流量节省模式,则不会自动播放。如果启用了节约模式,则在媒体设置中禁用自动播放。
尝试使用 mousemove 事件侦听器
var audio = document.createElement("AUDIO")
document.body.appendChild(audio);
audio.src = "./audio/rain.m4a"
document.body.addEventListener("mousemove", function () {
audio.play()
})
评论
Chrome 需要用户交互才能自动播放视频或通过 js (video.play()) 播放。 但互动可以是任何类型的,在任何时刻。 如果您只是在页面上随机单击,视频将自动播放。 然后我下定决心,添加一个按钮(仅在 chrome 浏览器上),上面写着“启用视频自动播放”。该按钮不执行任何操作,但只需单击它,即可进行任何后续视频所需的用户交互。
对我来说(在 Angular 项目中),这段代码有帮助:
在 HTML 中,您应该添加autoplay muted
在 JS/TS 中
playVideo() {
const media = this.videoplayer.nativeElement;
media.muted = true; // without this line it's not working although I have "muted" in HTML
media.play();
}
评论
@ViewChild()
@ViewChild('videoPlayer', {static: true}) videoplayer: ElementRef;
video: HTMLVideoElement;
this.video = this.videoplayer.nativeElement;
@ ngOnInit()
我在尝试播放音频文件时遇到了类似的错误。起初,它正在工作,然后当我开始在同一函数中使用 ChangeDetector 的方法在承诺解析时触发重新渲染时它停止工作(我在视图渲染方面遇到了问题)。markForCheck
当我更改为它时,它又开始工作了。我真的无法解释发生了什么,我只是想把这个放在这里,也许它会帮助某人。markForCheck
detectChanges
扩展 DOM 元素,处理错误,并正常降级
下面我使用 prototype 函数来包装原生的 DOM play 函数,抓住它的承诺,然后在浏览器抛出异常时降级为播放按钮。此扩展解决了浏览器的缺点,并且可以在任何了解目标元素的页面中即插即用。
// JavaScript
// Wrap the native DOM audio element play function and handle any autoplay errors
Audio.prototype.play = (function(play) {
return function () {
var audio = this,
args = arguments,
promise = play.apply(audio, args);
if (promise !== undefined) {
promise.catch(_ => {
// Autoplay was prevented. This is optional, but add a button to start playing.
var el = document.createElement("button");
el.innerHTML = "Play";
el.addEventListener("click", function(){play.apply(audio, args);});
this.parentNode.insertBefore(el, this.nextSibling)
});
}
};
})(Audio.prototype.play);
// Try automatically playing our audio via script. This would normally trigger and error.
document.getElementById('MyAudioElement').play()
<!-- HTML -->
<audio id="MyAudioElement" autoplay>
<source src="https://www.w3schools.com/html/horse.ogg" type="audio/ogg">
<source src="https://www.w3schools.com/html/horse.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
评论
您应该在 your 中添加属性,以便代码按预期工作。看下面..muted
videoElement
<video id="IPcamerastream" muted="muted" autoplay src="videoplayback%20(1).mp4" width="960" height="540"></video>
不要忘记添加有效的视频链接作为源
就我而言,我必须这样做
// Initialization in the dom
// Consider the muted attribute
<audio id="notification" src="path/to/sound.mp3" muted></audio>
// in the js code unmute the audio once the event happened
document.getElementById('notification').muted = false;
document.getElementById('notification').play();
评论
根据新的浏览器策略,用户必须先与 DOM 交互,然后才能播放 Audio 元素。
如果你想在页面加载时播放媒体,那么你可以简单地将autoplay属性添加到HTML中的音频元素,如下所示
<video id="video" src="./music.mp4" autoplay>
或者如果你不想做自动播放,那么你可以使用 Javascript 来处理这个问题。由于 autoplay 属性设置为 true,因此将播放媒体,我们只需将媒体静音即可。
document.getElementById('video').autoplay = true;
document.getElementById('video').muted = true;
Imp:现在,每当您播放媒体时,请不要忘记将 muted 属性设置为 false。喜欢这个
document.getElementById('video').muted = false;
document.getElementById('video').play();
或者,您也可以显示一个简单的弹出窗口,用户将在其中单击模式中的允许按钮。所以他先和 DOM 交互,然后你就不需要做任何事情了
我收到此错误
未捕获(承诺中) DOMException:play() 失败,因为用户没有先与文档交互。
这是我在我的 Angular 项目中所做的
关键点:永远不要假设视频会播放,也不要在视频实际未播放时显示暂停按钮。
您应该始终查看 play 函数返回的 Promise,看看它是否被拒绝:
ngOnInit(): void{
this.ensureVideoPlays();
}
private ensureVideoPlays(): void{
const video = document.querySelector("video");
if(!video) return;
const promise = video.play();
if(promise !== undefined){
promise.then(() => {
// Autoplay started
}).catch(error => {
// Autoplay was prevented.
video.muted = true;
video.play();
});
}
}
来源:自动播放政策
评论
我遇到了类似的问题,我需要在不静音的情况下播放视频。我这样做的方式是等待一秒钟,然后通过按钮触发事件。这是我的代码
if (playVideo == '1') {
setTimeout(function() {
$("#watch_video_btn").trigger('click');
}, 1000);
}
评论
音频自动播放属性在 MS Edge 中不起作用
我更改了我的 UI,让用户按下按钮来加载网站(当他们单击按钮后加载网站时,会播放音频)
由于它们与 DOM 交互,因此音频会播放!!
评论
就我而言,它只是在开始时自动调用的咔哒声(我不介意它是否静音)。所以我使用:
const clickSound = new Audio('click.wav');
clickSound.play().catch(function (error) {
console.log("Chrome cannot play sound without user interaction first")});
以消除错误。
有一些编程解决方案可以绕过该功能。
一些例子是使用 Java 的 Robot 或 Autohotkey,作为 Chrome 层之上的另一种解决方案。但是 IMO 它不是很聪明。因此,我最喜欢的解决方法(虽然有点棘手)是使用 Chrome 扩展 API 中的 API。chrome.debugger
Input.dispatchMouseEvent
var __target = 1857385916; // -- replace here with the tab id you desire
var x = 360 // -- replace here with your desired position to emulate click
var y = 360 // -- here as well
var button = "right"
var clickCount = 1
chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
type: 'mousePressed',
x: x,
y: y,
button: button,
clickCount: clickCount,
}, () => {
chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
type: 'mouseReleased',
x: x,
y: y,
button: button,
clickCount: clickCount,
})
});
初学者注意事项:
创建一个Chrome扩展程序,其中background.js创建为上述脚本,manifest.json当然是在启用权限的情况下创建的。debugger
Chrome的菜单->“管理扩展程序”->启用“开发者模式”->“加载解压缩”以像往常一样加载扩展程序。
您可能想知道要模拟鼠标事件的所需选项卡的选项卡 ID。我制作的以下脚本可能有助于快速识别每个选项卡的 ID。
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.status === "complete" && tab.active && tab.url) {
var obj = {
tabId: tabId,
title: tab.title,
url: tab.url,
}
console.log("[(background) tab id logger]", obj, );
}
});
在manifest.json中添加“tabs”权限,重新加载扩展,点击“后台页面”打开后台脚本检查窗口,将上面的JavaScript脚本粘贴到控制台上运行脚本。如果您没有看到任何错误,请重新加载任何选项卡,您将很快看到控制台上记录的选项卡 ID。
评论