chapters字幕轨无法通过cuechange事件监听,必须用timeupdate手动比对时间或读取track.cues;需在mode为hidden/disabled时访问cues,跳转前保存mode、跳转后恢复并手动匹配,VTT时间建议用整数秒。

chapters字幕轨不能用cuechange事件监听
浏览器对 kind="chapters" 的处理和其他 kind(如 subtitles)完全不同:它不触发 textTrack.cuechange,也不把章节作为 TextTrackCue 对象暴露给 JS。这是最常踩的坑——你绑了事件却收不到任何回调,不是代码写错,是规范如此。
真正可用的方式只有两种:监听 timeupdate 手动比对当前时间点,或直接读取 track.trackKind 对应的 track.cues(注意:部分浏览器中 chapters 轨的 cues 可能为空或延迟就绪)。
-
chapters轨本质是导航用的,浏览器 UI(如 Chrome 地址栏时间轴缩略图)会自动消费它,但 JS 层面不提供“章节切换”事件 - 必须在
track.mode = "hidden"或"disabled"下才能安全读取track.cues;设为"showing"后,某些浏览器(如 Safari)会清空cues列表 - 章节 cue 的
text是纯文本,不支持 HTML;id字段通常为空,不能依赖它做映射
手动匹配当前时间点找章节标题
核心逻辑是:在 video.addEventListener("timeupdate", ...) 中遍历 track.cues,找出 startTime ≤ currentTime 的那个 cue。
注意 track.cues 是只读的 TextTrackCueList,不能用数组方法直接遍历,得转成数组或用 for 循环索引访问:
立即学习“前端免费学习笔记(深入)”;
video.addEventListener("timeupdate", () => {
const track = video.textTracks[0]; // 假设 chapters 在第一个轨
if (!track || track.kind !== "chapters") return;
const time = video.currentTime;
let activeChapter = null;
for (let i = 0; i < track.cues.length; i++) {
const cue = track.cues[i];
if (time >= cue.startTime && time < cue.endTime) {
activeChapter = cue;
break;
}
}
if (activeChapter) {
document.getElementById("chapter-title").textContent = activeChapter.text;
}
});
- 务必加
track.kind === "chapters"判断,避免误操作其他轨 - 不要用
Array.from(track.cues)—— 某些旧版 Edge 会报错;稳妥做法是for循环或track.cues[i] - 章节 cue 的
endTime可能为Infinity(比如最后一章),需单独处理边界
确保 track.cues 就绪后再读取
track.cues 不是立即可用的:VTT 文件加载、解析、绑定到 track 都有延迟。常见错误是 DOM 加载完就立刻读 cues.length,结果为 0。
可靠方式是监听 load 事件 + oncuechange(虽然对 chapters 无效,但它表示 track 已就绪)+ 轮询兜底:
const track = video.textTracks[0];
if (track.readyState === TextTrack.LOADED) {
readChapters(track);
} else {
track.addEventListener("load", () => readChapters(track));
// 兜底:1s 后再试一次(防 load 未触发)
setTimeout(() => readChapters(track), 1000);
}
-
TextTrack.LOADED是关键判断依据,不是readyState === 3(可读性差) - Chrome 中
chapters轨的load事件有时不触发,所以兜底轮询很必要 - 不要用
track.addEventListener("addcue", ...)—— 它只对动态添加 cue 有效,静态 VTT 不触发
章节跳转要绕过浏览器默认行为
点击章节标题想跳转时,不能直接 video.currentTime = cue.startTime 就完事。因为:chapters 轨本身不控制播放,且某些浏览器(如 Firefox)会在跳转后重置 track.mode,导致后续 cues 访问失败。
- 跳转前先缓存当前
track.mode,跳转后立即恢复(例如设回"hidden") - 跳转后触发一次手动 cue 匹配(调用上文的
readChapters),避免 UI 标题滞后一帧 - 避免在
timeupdate回调里修改currentTime,可能引发循环触发 - VTT 中章节时间点建议用整数秒(如
00:01:23.000),减少浮点误差导致的匹配失败
章节分段这事,表面是读个 cue,实际卡点全在时机和状态同步上——cues 就绪没?mode 被谁改了?timeupdate 频率够不够?漏掉任何一个,UI 就会掉帧或失同步。



















