track元素不能动态加载字幕,需通过JavaScript操作video.textTracks和track.mode;动态添加必须用video.appendChild()插入video内且立即设src,再监听load事件启用,或用addTextTrack()创建脚本轨道。

track 元素本身不能“动态加载”字幕内容——它只是声明轨道的元信息;真正能动态添加/启用/禁用轨道的,是 JavaScript 操作 video.textTracks 集合与 track.mode 属性。
为什么直接 new track() 或 innerHTML 插入不生效
浏览器对 track 元素有严格校验:只有作为 <video></video> 的**直接子元素**且在 DOM 加载完成前就存在(或通过 append() 等合法方式插入),才会被解析为有效轨道。用 innerHTML += '<track ...>'</track>、document.createElement('track') 后仅 append 到 video 外部,或插入时 video 尚未 ready,都会导致轨道静默失败,video.textTracks.length 不变。
- 常见错误现象:
console.log(video.textTracks)显示空列表,或新增的 track 始终mode === 'disabled'且无法设为'showing' - 根本原因:浏览器只在 video 初始化阶段扫描子
track元素;后续插入的需手动调用video.addTextTrack() - 注意:
addTextTrack()创建的是“脚本生成轨道”,不支持src,只能用 JS 动态写入 cue,适合实时字幕、AI 翻译流等场景,不适用于预存的 .vtt 文件
正确动态加载外部 .vtt 字幕的两种路径
若目标是加载一个远程 .vtt 文件(如用户点选语言后加载),必须走“先声明空 track + 后赋值 src + 监听加载完成”流程,不能跳过 DOM 插入步骤:
- 创建
track元素并插入到video内部(必须是 direct child):const t = document.createElement('track'); t.kind = 'subtitles'; t.srclang = 'ja'; t.label = '日本語'; video.appendChild(t); - 立即设置
src(不要延迟):t.src = 'ja.vtt'; - 监听
load事件(不是onload)确认加载成功:t.addEventListener('load', () => { t.mode = 'showing'; }); - 关键限制:.vtt 文件必须同源,或服务器返回
Access-Control-Allow-Origin: *,否则触发 CORS 错误且静默失败
用 textTracks API 动态切换已加载轨道
一旦多个 track 存在于 DOM 中(无论初始写死还是上述方式动态插入),就可以用原生 API 控制显示状态,无需重新加载文件:
立即学习“前端免费学习笔记(深入)”;
- 遍历所有轨道:
Array.from(video.textTracks).forEach(t => t.mode = t.srclang === 'zh' ? 'showing' : 'disabled'); - 只启用一个:
video.textTracks[0].mode = 'showing';(索引需确保存在) - 检查当前激活状态:
const active = Array.from(video.textTracks).find(t => t.mode === 'showing'); - 注意:
mode只能设为'disabled'、'hidden'或'showing';设为'showing'后,浏览器才真正解析并渲染该轨道的 cue
容易被忽略的兼容性细节
移动端 Safari 和部分 Android 浏览器对动态 track 支持不稳定:即使 src 加载成功,mode = 'showing' 也可能被忽略,或只在用户手动打开字幕菜单后才生效。此时必须降级处理——提前把所有语言的 track 全部写死在 HTML 中(哪怕初始 default 只设一个),再用 JS 切换 mode,这是目前最稳妥的方案。



















