直接修改 的 textContent 或 innerHTML 无效,因其仅为元信息容器;应使用 VTTCue 动态注入字幕,或用绝对定位 div 覆盖模拟,多语言切换时优先通过 track.mode 控制。

用 textContent 或 innerHTML 直接改 <track></track> 标签内容行不通
HTML 的 <track></track> 标签本身不支持运行时动态替换字幕文本——它只是个元信息容器,指向外部 WebVTT 文件或声明内联轨道,浏览器不会让你通过 JS 修改它的 textContent 来实时刷新字幕显示。你看到的字幕是 <video></video> 元素内部由浏览器渲染引擎解析并叠加的,不是普通 DOM 文本节点。
常见错误现象:document.querySelector('track').textContent = '新字幕' 执行后界面毫无变化;或者修改了 track 的 src 属性但没触发重载,字幕仍卡在旧内容。
-
<track></track>的src指向的是静态 .vtt 文件,改完属性必须手动调用load()重新加载整个视频资源(会闪屏/中断播放) - 内联
<track kind="subtitles"><source src="sub.vtt"></source></track>写法无效,<track></track>不接受子元素 - 试图用
dataset存字幕状态(如data-current-line)完全没用——它不驱动任何渲染逻辑
真正无刷新换字幕:用 VTTCue + TextTrackCueList 动态注入
现代浏览器支持通过 JavaScript 创建并插入原生字幕条目(VTTCue),绕过外部文件依赖,实现毫秒级内容替换。前提是视频已挂载 <track kind="subtitles"></track> 并设为 mode = "showing"。
实操关键三步:
立即学习“前端免费学习笔记(深入)”;
- 先获取目标轨道:
const track = video.textTracks[0](注意索引,textTracks是实时列表,需确保kind === 'subtitles'且mode !== 'disabled') - 清除旧条目:
track.cues?.forEach(cue => track.removeCue(cue))(cues是只读类数组,必须用removeCue) - 新建并添加:
const cue = new VTTCue(0, 10, '这是动态字幕'); track.addCue(cue)(起始/结束时间单位为秒,支持小数)
注意:多次快速调用 addCue 可能导致重复叠加,建议每次操作前清空;VTTCue 不支持 HTML 标签,纯文本,若需样式请走 CSS ::cue 伪元素。
兼容老浏览器或需富文本?用覆盖层 div 模拟字幕
当目标环境不支持 VTTCue(如 IE、旧版 Safari),或你需要插入带链接、高亮、多行排版的字幕时,放弃原生 <track></track>,改用绝对定位的 <div id="subtitle-overlay"> 覆盖在视频上。
<p>这种方式完全可控,但需手动同步播放进度:</p>
<ul>
<li>监听 <code>video.ontimeupdate,根据当前 currentTime 查找匹配字幕片段(建议预存为数组:[{start: 12.5, end: 14.2, text: '你好'}])
innerHTML 更新 overlay 内容,支持任意 HTML:overlay.innerHTML = '<strong>重点</strong>提示'
requestAnimationFrame)更新position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%),避免遮挡控制栏换语言字幕时,track.mode 切换比删重建更稳
如果只是切换不同语言的字幕轨道(比如中/英/日),不要反复移除再添加 <track></track> 标签——DOM 操作慢,且可能触发视频重载。正确做法是预先加载所有轨道,仅切换 mode 属性。
示例结构:
<video id="myVideo"> <source src="movie.mp4"> <track kind="subtitles" src="zh.vtt" srclang="zh" label="中文" default> <track kind="subtitles" src="en.vtt" srclang="en" label="English"> </video>
切换逻辑:
- 遍历
video.textTracks,对非目标轨道设track.mode = 'disabled' - 对目标轨道设
track.mode = 'showing'(不是'hidden',否则不显示) - 注意:
mode为'showing'时,浏览器自动加载并解析对应src,无需额外 fetch - 首次设置
default属性的轨道会自动生效,但后续切换必须显式改mode,否则无效
最易被忽略的一点:多个 <track></track> 必须有唯一 srclang,否则 textTracks 列表里可能无法准确识别目标轨道——别靠顺序索引取,要用 track.language === 'zh' 判断。



















