我一直在尝试使用HTML5和Jquery创建自定义媒体播放器。
我遵循不同的方法,并根据我刷新页面的方式遇到了一些麻烦。
第一个案例
$(document).ready(function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
在这种情况下,当我通过按地址栏中的ENTER
键将页面重定向到同一URL时,持续时间返回NaN。但是,当我使用reload button
或按F5
按钮进行刷新时,它完全正常。
第二种情况
我在一些答案中读到loadedmetadata
事件后的加载持续时间可能会有所帮助。所以我尝试了以下内容:
$(document).ready(function(){
$('audio').on('loadedmetadata', function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
});
令人惊讶的是,在这种情况下,发生了第一种情况的反转。在重定向的情况下,持续时间显示完全正常,即在地址栏中按ENTER
。但是,在使用F5
按钮或reload button
进行刷新的情况下,持续时间根本不会显示,甚至NaN也不会导致我认为代码没有被执行所有
进一步阅读建议这可能是webkit浏览器中的一个错误,但我找不到任何结论性或有帮助的。
这种奇特行为背后的原因是什么? 如果你能解释它并解决这个问题,那就太棒了。
编辑: 我主要是在寻找这种行为差异背后的解释。我想了解在重定向和刷新的情况下渲染页面背后的机制。
答案 0 :(得分:3)
听起来问题是事件处理程序设置得太晚,即音频文件在文档准备好之前加载了元数据。
尝试删除$(document).ready
调用
$('audio').on('loadedmetadata', function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
请注意,这需要<script>
标记位于文档中的<audio>
标记之后。
或者,您可以略微调整逻辑,以便更新持续时间的代码始终运行(但如果获得NaN
则优雅地失败):
function updateDuration() {
var duration = Math.ceil($('audio')[0].duration);
if (duration)
$('#duration').html(duration);
}
$(document).ready(function(){
$('audio').on('loadedmetadata', updateDuration);
updateDuration();
});
答案 1 :(得分:1)
可爱的代码示例和来自人们的东西 - 但解释实际上非常简单。
如果文件已经在缓存中,那么loadedmetadata
事件将不会触发(也不会触发许多其他事件 - 主要是因为它们在您附加侦听器时已经触发)和{{ 1}}将被设置。如果它不在缓存中,则duration
将为duration
,并且该事件将会触发。
解决方案很简单。
NaN
我在代码注释中包含了jQuery备选方案。
答案 2 :(得分:0)
根据w3 spec,当持续时间返回NaN时,这是标准行为。
所以我建议使用durationchange
事件:
$('audio').on('durationchange', function(){
var duration = $('audio')[0].duration;
if(!isNaN(duration)) {
$('#duration').html(Math.ceil(duration));
}
});
注意:如果您在页面上有多个audio
元素,则此代码(以及您的代码)将无法正常工作。原因是您从页面上的所有audio
元素中侦听事件,并且每个元素将触发自己的事件:
$('audio').on('durationchange', function(){...});
OR
您可以尝试:
<script>
function durationchange() {
var duration = $('audio')[0].duration;
if(!isNaN(duration)) {
$('#duration').html(Math.ceil(duration));
}
}
</script>
<audio ondurationchange="durationchange()">
<source src="test.mp3" type="audio/mpeg">
</audio>
答案 3 :(得分:0)
请注意,不同浏览器的行为会有所不同。在Chrome上,您有不同类型的加载。当资源不在cache
时,它将获取完整文件(例如js或css),或者是文件的一部分(例如mp3)。此部分文件包含metadata
,允许浏览器确定持续时间和其他数据,例如以此速率下载整个文件所需的时间,例如canplay
或canplaythrough
事件。如果您查看开发控制台中的网络使用情况,您会看到HTTP status code
将是200(成功加载)或206(部分加载 - 例如mp3)。
点击refresh
时,会检查元素是否已更改。 HTTP状态将为304
,表示文件尚未修改。如果它没有更改并且仍在浏览器缓存中,则不会下载它。确定是否已更改的调用来自提供文件的服务器。
当您只需点击地址栏中的输入时,它就会自动从缓存中获取,而不是在线验证。所以它要快得多。
因此,根据您调用或刷新页面的方式(无论是简单输入,刷新还是完全刷新而不使用缓存),您从mp3获得metadata
的那一刻就会有很大差异。在从缓存直接获取元数据与向服务器发出请求之间,差异可能是几百毫秒,这足以改变不同时刻可用的数据。
话虽如此,听loadedmetada
应该给出一致的结果。加载具有持续时间信息的数据时会触发此事件,因此无论页面加载的方式如何,都应该正确地进行调用。此时,您必须考虑其他元素的干扰。你应该做的是通过各种事件跟踪你的音频,以获得它在不同时刻的确切位置。因此,在准备好文档时,您可以为不同的事件添加侦听器,并查看问题发生的位置。像这样:
$('audio')[0].addEventListener('loadstart', check_event)
$('audio')[0].addEventListener('loadeddata', check_event)
$('audio')[0].addEventListener('loadedmetadata', check_event)//at this point you should be able to call duration
$('audio')[0].addEventListener('canplay', check_event) //and so on
function check_event(e) {
console.log(e.target, e.type)
}
您会看到,根据您刷新的方式,这些事件可能会在不同的时刻出现,也许会解释您输出中的不一致。