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