track元素默认不生效是因为它初始mode为disabled,需通过video.textTracks[i].mode='showing'启用;且必须在loadedmetadata事件后操作,确保轨道已加载并检查readyState为2。

track元素为什么默认不生效
HTML里的 <track></track> 标签本身是惰性的——它只是声明存在字幕/描述/章节等轨道资源,但不会自动加载或显示。浏览器只在关联的 <video></video> 或 <audio></audio> 元素明确启用对应轨道时才开始解析和渲染。常见误区是以为加了 <track kind="subtitles" src="zh.vtt"></track> 就能立刻看到字幕,其实它默认处于 disabled 状态。
用JavaScript手动启用track的正确姿势
必须先获取到 track 元素对应的 TextTrack 对象,再修改其 mode 属性。直接操作 DOM 节点的 disabled 属性无效(那是 HTML 属性,不是运行时状态)。
实操要点:
-
<track></track>必须已插入文档且父媒体元素已加载元数据(loadedmetadata事件后才可安全访问textTracks) - 通过
video.textTracks[i]获取轨道对象,不能用document.querySelector('track')直接调用mode - 合法的
mode值只有三个:"disabled"、"hidden"、"showing";设为"showing"才会渲染字幕 - 如果
src是跨域资源,需确保服务器返回Access-Control-Allow-Origin,否则轨道加载失败且静默失败(无错误提示)
示例:
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
const video = document.querySelector('video');
video.addEventListener('loadedmetadata', () => {
const track = video.textTracks[0]; // 注意:不是 document.querySelector('track')
if (track) {
track.mode = 'showing'; // 关键:必须设为 showing
}
});
动态添加track并立即启用的坑
用 video.addTextTrack() 创建新轨道时,返回的 TextTrack 对象初始 mode 是 "disabled",且不能直接设置 src——它只适用于内联内容(如用 addCue() 插入字幕)。若要加载外部 VTT 文件,仍得用 HTML <track></track> 标签或动态创建后插入 DOM,再等 load 事件。
常见错误现象:
- 调用
addTextTrack('subtitles').mode = 'showing'后字幕不出现 → 因为没内容,也没触发加载流程 - 动态创建
<track></track>并appendChild到<video></video>后立刻设mode→ 失败,因轨道尚未初始化,textTracks长度还没更新 - 多个
<track></track>时误用索引,比如textTracks[0]实际是浏览器自动生成的metadata轨道而非你的字幕
检查track是否真正就绪的可靠方式
光看 mode === 'showing' 不够,还要确认 readyState 是 2(LOADED),否则字幕文件可能还在请求中或解析失败。VTT 解析错误(如格式错、BOM 头)通常不会抛 JS 异常,只会让 readyState 停留在 0(NOT_LOADED)或 1(LOADING)。
建议检查逻辑:
- 监听
textTracks的addtrack事件,比轮询更可靠 - 对每个新轨道监听
onload和onerror(注意:部分浏览器不支持onerror,需降级检查readyState) - 用
track.cues.length > 0辅助判断内容是否已加载成功(需在load后)
容易被忽略的是:某些旧版 Safari 对 <track></track> 的 default 属性响应延迟,即使设了 default,脚本里读 mode 可能仍是 "disabled",必须显式赋值。


















