Javascript Firefox 不会调用 HTML5 视频的 canplay/canplaythrough 事件。为什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10235919/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
The canplay/canplaythrough events for an HTML5 video are not called on Firefox. Why?
提问by Gabriel
I'm building a jQuery plugin for managing HTML5 videos. I'm trying to capture the canplay and canplaythrough events. In Chrome, the event is fired without problem. In Firefox, sometime it's triggered, sometime it's not.
我正在构建一个用于管理 HTML5 视频的 jQuery 插件。我正在尝试捕获 canplay 和 canplaythrough 事件。在 Chrome 中,该事件被毫无问题地触发。在 Firefox 中,有时会触发,有时不会。
I'm simplifying my code a little here:
我在这里稍微简化了我的代码:
$('#my_video').on('canplay canplaythrough', function(){
console.log('canplay event fired');
});
I also tried with the native javascript .addEventListener() and it's not working.
我也尝试过使用原生 javascript .addEventListener() 但它不起作用。
Any idea why the event is not called on Firefox and how to fix that?
知道为什么没有在 Firefox 上调用该事件以及如何解决这个问题吗?
NOTE: Please do not tell me to use one of the already available plugins like jplayer and video-js, I know that they exist and work well, but I have to build an in-house solution.
注意:请不要告诉我使用 jplayer 和 video-js 等已经可用的插件之一,我知道它们存在并且运行良好,但我必须构建一个内部解决方案。
回答by Pierre Spring
The problem is that your video
element has triggered the canplaythrough
event before you registered the event handler.
问题是您的video
元素canplaythrough
在注册事件处理程序之前触发了事件。
As you pointed out in your own answer, you can put your scripts in the <head>
, but this is bad for your page performance.
正如您在自己的回答中指出的那样,您可以将脚本放在 中<head>
,但这对您的页面性能不利。
A better way to fix your problem is to check the readystate
attribute and execute your function manually in that case:
readystate
在这种情况下,解决问题的更好方法是检查属性并手动执行函数:
var $video = $('video'),
videoElement = $video[0];
$video.on('canplaythrough', callback);
// If the video is in the cache of the browser,
// the 'canplaythrough' event might have been triggered
// before we registered the event handler.
if (videoElement.readyState > 3) {
callback();
}
回答by Clayton Gulick
The most likely reason you're seeing this probably has to do with timing issues. You stated in your accepted answer that putting jQuery into the head rather than the footer solves the problem. This tells me that the issue is DOM parsing and script execution order. The most likely culprit is that the "canplay" and "canplaythrough" events were being fired before jquery and your page script were parsed and the event handlers added - but only sometimes, depending on network traffic and load times. By putting the script in the head, you forced your event binding to occur before the DOM elements were created, thereby ensuring that you didn't miss any events.
您看到这种情况的最可能原因可能与时间问题有关。您在接受的答案中表示,将 jQuery 放入头部而不是页脚可以解决问题。这告诉我问题在于 DOM 解析和脚本执行顺序。最可能的罪魁祸首是“canplay”和“canplaythrough”事件在 jquery 和您的页面脚本被解析并添加事件处理程序之前被触发 - 但只是有时,取决于网络流量和加载时间。通过将脚本放在头部,您可以强制在创建 DOM 元素之前进行事件绑定,从而确保不会错过任何事件。
As an aside, the performance benefits of putting script elements at the bottom of the page are debatable. If you really want to tweak page performance, use something like LABjs to manage parallel script loading.
顺便说一句,将脚本元素放在页面底部的性能优势值得商榷。如果您真的想调整页面性能,请使用 LABjs 之类的东西来管理并行脚本加载。
回答by Gabriel
Even if my question didn't get any attention whatsoever, I think it's a good idea to give an explanation for people who may stumble on this in the future...
即使我的问题没有得到任何关注,我认为为将来可能会偶然发现此问题的人提供解释是个好主意......
The problem is really weird: if the jQuery core is included in the footer, some of the video events do not work. If the jQuery core is included in the head of the document, all events are called correctly.
问题真的很奇怪:如果页脚中包含 jQuery 核心,则某些视频事件不起作用。如果 jQuery 核心包含在文档的头部,则所有事件都会被正确调用。
So the solution is to include the jQuery core in the html head even if "best practices" for optimization recommends placing all script at the end of the body for faster loading times.
因此,解决方案是将 jQuery 核心包含在 html 头中,即使优化的“最佳实践”建议将所有脚本放在正文的末尾以加快加载时间。
回答by RCNeil
In my case, this was determined by the preload
attribute specified for the element. I did not have it specified at all, so different browsers were choosing to do different things.
就我而言,这是由preload
为元素指定的属性决定的。我根本没有指定它,所以不同的浏览器选择做不同的事情。
Once I specified preload="auto"
, the on("canplay")
event handler worked fine/as expected.
一旦我指定preload="auto"
,on("canplay")
事件处理程序就可以正常工作/按预期工作。
回答by Kolyunya
If you expect the Firefox to load the whole audio after you trigger load
then it would not do this. It will fire the loadstart
but will not download anything. No progress
events will be fired. And it will actually do no request to that file. You can see this behavior in the Firebug.
如果您希望 Firefox 在您触发后加载整个音频,load
那么它不会这样做。它会触发loadstart
但不会下载任何东西。不会progress
触发任何事件。它实际上不会对该文件提出任何请求。您可以在 Firebug 中看到这种行为。
Firefox will only start loading the file after you trigger 'play`.
Firefox 只会在您触发“播放”后才开始加载文件。
Proof. See console output.
证明。请参阅控制台输出。
回答by George Huber
I do also think this is a race condition. The way I got around it is as follows:
我也认为这是一个竞争条件。我绕过它的方式如下:
In the HTML of the video element add the attribute preload="metadata" - to just preload the video metadata. So:
在视频元素的 HTML 中添加属性 preload="metadata" - 只预加载视频元数据。所以:
<video id="myVideo" width="640" height="480" preload="metadata" />
Next, inside the JS:
接下来,在JS内部:
var $vid = $("#myVideo");
$vid.bind("canplaythrough", console.log("can play through full video"));
$vid.get(0).load();
This logged the message for me in Chrome - haven't tested elsewhere.
这在 Chrome 中为我记录了消息 - 没有在其他地方测试过。
回答by Troy Valle
Adding:
添加:
var video = $('video');
video.trigger('load');
Afteradding the canplaythrough event listener fixed it for me on Firefox and Safari.
后加入canplaythrough事件侦听器固定它,我在Firefox和Safari。
回答by Friedrich Siever
After 1.5 days of trying different approaches from here (in vanilla). The events "canplay" and "canplaythrough" with addEventListner don't work in Edge. They work fine in every other Browser. So I ended up with a check of "ready-state" with setTimout :-(. Not realy elegant, but it works for me.
经过 1.5 天从这里尝试不同的方法(在香草中)。带有 addEventListner 的事件“canplay”和“canplaythrough”在 Edge 中不起作用。它们在其他所有浏览器中都能正常工作。所以我最终用 setTimout :-( 来检查“就绪状态”。不是很优雅,但它对我有用。
Controller.prototype.backGroundControl = function () {
var vid = document.querySelector('#bgvid');
var bgImg = document.querySelector('#bgimg');
_this = this;
if (vid.readyState === 4){
bgImg.style.opacity = "0"
} else{
setTimeout(function(){
_this.backGroundControl();
},500)
}
}
}