onseeked事件在媒体元素跳转到新位置且该位置数据已缓冲可播放时触发;需先注册监听器再设置currentTime,移动端需注意用户手势限制及关键帧对齐偏差。

onseeked 事件什么时候触发
onseeked 是 HTML <video> 和 <audio> 元素的原生事件,它在用户拖动进度条(或调用 currentTime 赋值)导致播放位置改变后,**且新位置的媒体数据已加载并可播放时**触发。注意:不是“开始跳转时”,也不是“刚设完 currentTime 就触发”——它依赖底层缓冲状态。
为什么直接赋值 currentTime 后 onseeked 不立刻触发
常见错误是这样写:
video.currentTime = 120;
video.onseeked = () => console.log('跳完了'); // ❌ 很可能不执行
原因有二:
-
currentTime设为 120 秒时,如果该时间点的数据尚未缓冲(比如视频未预加载、网络慢、或使用了preload="metadata"),浏览器会进入seeking状态但无法立即完成,onseeked就不会触发 - 事件监听必须在设置
currentTime之前注册,否则可能错过异步完成时机
正确做法是:
立即学习“前端免费学习笔记(深入)”;
video.onseeked = () => console.log('跳转完成');
video.currentTime = 120; // 在监听器挂好之后再设
如何可靠判断跳转是否真正完成(含失败兜底)
onseeked 只告诉你“跳成功了”,但不告诉你“为什么没跳”。实际开发中更常遇到的是 onseeking 一直持续、onseeked 死活不触发。这时需要结合其他信号:
- 监听
onseeking+onstalled或onerror做超时 fallback - 检查
video.readyState是否 ≥ 2(HAVE_FUTURE_DATA)且video.seeking === false - 对
currentTime赋值后轮询检测(仅作保底,不推荐高频)
一个轻量级健壮写法:
function seekTo(video, time) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error('seek timeout')), 5000);
const onSeeked = () => {
clearTimeout(timeout);
video.removeEventListener('seeked', onSeeked);
resolve();
};
video.addEventListener('seeked', onSeeked);
video.currentTime = time;
});
}
// 使用
seekTo(video, 120).then(() => console.log('ok')).catch(err => console.error(err));
兼容性与移动端特殊行为
桌面 Chrome/Firefox/Safari 均支持 onseeked,但 iOS Safari 有个关键限制:只有用户手势触发的跳转(如手动拖进度条)才会触发 onseeked;脚本调用 currentTime 在静音/自动播放策略下大概率被阻塞,且不会触发该事件。
这意味着:
- 移动端想靠 JS 跳转后做 UI 同步(比如高亮字幕),不能只依赖
onseeked - 必须配合
video.ended、timeupdate(注意节流)、或playing事件交叉验证 - 部分安卓 WebView 对
seeked触发时机不一致,建议加 100ms 延迟再读currentTime确认最终值
最易被忽略的一点:即使 onseeked 触发了,video.currentTime 的实际值也可能因关键帧对齐而略大于你设的值(比如设 120.3,实际跳到 120.324)。别拿它做精确时间比对。



















