Firefox上不会调用HTML5video的canplay / canplaythrough事件。 为什么?

我正在构建一个用于管理HTML5video的jQuery插件。 我正在尝试捕捉canplay和canplaythrough事件。 在Chrome中,该事件被解雇没有问题。 在Firefox中,某些时候它被触发,有时它不是。

我在这里简化了我的代码:

$('#my_video').on('canplay canplaythrough', function(){ console.log('canplay event fired'); }); 

我也尝试使用原生的javascript .addEventListener()并且它不起作用。

知道为什么没有在Firefox上调用该事件以及如何解决这个问题?

注意:请不要告诉我使用已经可用的插件,如jplayer和video-js,我知道它们存在并运行良好,但我必须构建一个内部解决方案。

问题是,在注册事件处理程序之前,您的video元素已触发canplaythrough事件。

正如您在自己的回答中指出的那样,您可以将脚本放在 ,但这对您的页面性能不利。

解决问题的更好方法是检查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(); } 

你看到这个的最可能的原因可能与时间问题有关。 你在接受的答案中说过,将jQuery放入头部而不是页脚可以解决问题。 这告诉我问题是DOM解析和脚本执行顺序。 最可能的罪魁祸首是在jquery之前触发了“canplay”和“canplaythrough”事件,并且解析了您的页面脚本并添加了事件处理程序 – 但有时仅取决于网络流量和加载时间。 通过将脚本放在头部,您强制在创建DOM元素之前进行事件绑定,从而确保您不会错过任何事件。

顺便说一句,将脚本元素放在页面底部的性能优势是值得商榷的。 如果您确实想要调整页面性能,请使用LABjs之类的东西来管理并行脚本加载。

即使我的问题没有得到任何关注,我认为对将来可能偶然发现的人做出解释是个好主意…

问题非常奇怪:如果页脚中包含jQuery核心,则某些video事件不起作用。 如果jQuery核心包含在文档的头部,则会正确调用所有事件。

所以解决方案是将jQuery核心包含在html头中,即使优化的“最佳实践”建议将所有脚本放在正文的末尾以加快加载时间。

我也认为这是一种竞争条件。 我解决它的方式如下:

在video元素的HTML中添加属性preload =“metadata” – 只是预加载video元数据。 所以:

  

接下来,在JS里面:

 var $vid = $("#myVideo"); $vid.bind("canplaythrough", console.log("can play through full video")); $vid.get(0).load(); 

这在Chrome中为我记录了这条消息 – 尚未在其他地方测试过。

如果您希望Firefox在触发load后加载整个音频,那么它就不会这样做。 它将触发loadstart但不会下载任何内容。 不会触发任何progress事件。 它实际上不会对该文件发出任何请求。 您可以在Firebug中看到此行为。

Firefox只会在您触发’play`后开始加载文件。

certificate 。 查看控制台输出。

在我的例子中,这是由为元素指定的preload属性决定的。 我没有指定它,所以不同的浏览器选择做不同的事情。

一旦我指定了preload="auto"on("canplay")事件处理程序就可以正常工作了。

添加:

 var video = $('video'); video.trigger('load'); 

添加canplaythrough事件监听器后,在Firefox和Safari上为我修复了它。

经过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) } 

}