Firefox 不会调用 HTML5 视频的 canplay/canplaythrough 事件。为啥?
Posted
技术标签:
【中文标题】Firefox 不会调用 HTML5 视频的 canplay/canplaythrough 事件。为啥?【英文标题】:The canplay/canplaythrough events for an HTML5 video are not called on Firefox. Why?Firefox 不会调用 HTML5 视频的 canplay/canplaythrough 事件。为什么? 【发布时间】:2012-05-01 10:19:55 【问题描述】:我正在构建一个用于管理 html5 视频的 jQuery 插件。我正在尝试捕获 canplay 和 canplaythrough 事件。在 Chrome 中,事件被触发没有问题。在 Firefox 中,有时会触发,有时不会。
我在这里稍微简化一下我的代码:
$('#my_video').on('canplay canplaythrough', function()
console.log('canplay event fired');
);
我也尝试使用原生 javascript .addEventListener(),但它不起作用。
知道为什么在 Firefox 上没有调用该事件以及如何解决这个问题吗?
注意:请不要告诉我使用已经可用的插件之一,例如 jplayer 和 video-js,我知道它们存在并且运行良好,但我必须构建一个内部解决方案。
【问题讨论】:
【参考方案1】:问题是您的video
元素在您注册事件处理程序之前触发了canplaythrough
事件。
正如您在自己的回答中指出的那样,您可以将脚本放在<head>
中,但这对您的页面性能不利。
解决问题的更好方法是检查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();
【讨论】:
最佳答案!检查视频就绪状态,如果 readyState 不是4
或更高,则添加事件监听器。
惊人的答案!就是这个。谢谢!!!! @Gabriel 你应该把它标记为肯定的答案
将脚本放在头部是不好的:整体编写脚本并显示缺乏不理解的标准:使用defer
属性,将脚本放在头部并且仍然具有相同的性能。
@John:我很确定将<script>
标记添加到带有<head>
的defer
会导致与@Gabriel 描述的相同的问题。
不,您总是将脚本保留在 head 元素中,然后然后解决问题。将脚本移动到 body
元素是不好的做法,甚至考虑在 body
和 head
元素之间移动脚本也是对 JavaScript 的业余水平理解。【参考方案2】:
您看到此问题的最可能原因可能与时间问题有关。您在接受的答案中表示,将 jQuery 放在头部而不是页脚可以解决问题。这告诉我问题在于 DOM 解析和脚本执行顺序。最可能的罪魁祸首是“canplay”和“canplaythrough”事件在 jquery 和您的页面脚本被解析并添加事件处理程序之前被触发 - 但只是有时,取决于网络流量和加载时间。通过将脚本放在头部,您强制在创建 DOM 元素之前发生事件绑定,从而确保您不会错过任何事件。
顺便说一句,将脚本元素放在页面底部的性能优势值得商榷。如果您真的想调整页面性能,请使用 LABjs 之类的工具来管理并行脚本加载。
【讨论】:
【参考方案3】:在我的例子中,这是由为元素指定的preload
属性确定的。我根本没有指定它,所以不同的浏览器选择做不同的事情。
一旦我指定了preload="auto"
,on("canplay")
事件处理程序就可以正常工作/符合预期。
【讨论】:
【参考方案4】:即使我的问题没有引起任何关注,我认为为将来可能偶然发现此问题的人提供一个解释是个好主意...
问题真的很奇怪:如果 jQuery 核心包含在页脚中,则某些视频事件不起作用。如果 jQuery 核心包含在文档的头部,则所有事件都被正确调用。
因此解决方案是在 html 头部包含 jQuery 核心,即使优化的“最佳实践”建议将所有脚本放在正文末尾以加快加载时间。
【讨论】:
我敢打赌它实际上是一个竞争条件,canplay
和 canplaythrough
事件被触发 before jQuery 附加事件侦听器。编辑:刚刚注意到 Clayton Gulick 讨论了下面的问题。
或者您可以使用 javascript 来连接事件侦听器,然后以编程方式设置视频的 src 属性。您可以将 src 存储在 data-src 属性中,然后运行 videoElement.src = videoElement.dataset['src']
。【参考方案5】:
我也确实认为这是一种竞争条件。我绕过它的方法如下:
在视频元素的 HTML 中添加属性 preload="metadata" - 仅预加载视频元数据。所以:
<video id="myVideo" preload="metadata" />
接下来,在 JS 内部:
var $vid = $("#myVideo");
$vid.bind("canplaythrough", console.log("can play through full video"));
$vid.get(0).load();
这在 Chrome 中为我记录了消息 - 尚未在其他地方测试。
【讨论】:
【参考方案6】:如果您希望 Firefox 在您触发 load
后加载整个音频,那么它不会这样做。它将触发loadstart
,但不会下载任何内容。不会触发 progress
事件。它实际上不会对该文件提出任何请求。您可以在 Firebug 中看到这种行为。
Firefox 只会在您触发“播放”后开始加载文件。
Proof。查看控制台输出。
【讨论】:
其实这种行为是意料之中的,可以通过视频的preload属性来控制 @NamanGoelThe preload attribute specifies if and how the author thinks that the audio file should be loaded when the **page loads**.
据我所知,preload
与 audio.load()
无关。相反,当没有对音频执行任何操作时,它会更改浏览器行为。如果我弄错了,请指出我的文档。是否可以在页面加载时强制音频不加载,而是在触发load()
时完全加载?
我现在无法处理链接。但据我所知,浏览器不应该加载音频,除非它有preload
attr。无论如何,有些浏览器会预先加载音频/视频,看起来很快。【参考方案7】:
添加:
var video = $('video');
video.trigger('load');
之后添加 canplaythrough 事件侦听器为我在 Firefox 和 Safari 上修复了它。
【讨论】:
【参考方案8】:从这里尝试不同的方法 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)
【讨论】:
以上是关于Firefox 不会调用 HTML5 视频的 canplay/canplaythrough 事件。为啥?的主要内容,如果未能解决你的问题,请参考以下文章