track 元素本身不触发 DOM 变更事件,监听需转向 TextTrack 对象:用 video.textTracks.onaddtrack 捕获新增、onload/onerror 监听加载、轮询 mode 检测用户切换,且 data-track 无效。

track 元素本身不会主动触发 DOM 变更事件,监听它的“变更”本质是监听其属性(src、mode、readyState)或父 video/audio 的轨道列表变化——不能靠 DOMSubtreeModified,它已被废弃且不触发;也不能靠轮询 textTracks.length,效率低且漏状态。
为什么 MutationObserver 无法直接捕获 track 内容加载或 mode 切换
MutationObserver 只响应 DOM 树结构或属性的显式修改,而 track 的关键行为由浏览器内部驱动:
-
src加载成功/失败不触发 attribute change(除非你手动setAttribute('src', ...)) -
mode改变(如track.mode = 'showing')不是 DOM 属性变更,而是 JS 属性赋值,MutationObserver完全感知不到 -
readyState是只读属性,变化时无任何事件通知 - 浏览器自动匹配
srclang并启用轨道的过程完全静默,不写回 DOM
正确监听 track 状态变更的两个可靠入口
必须绕过 DOM,直接观察 HTMLMediaElement.textTracks 列表及其子项:
- 用
video.addEventListener('load', ...)或video.addEventListener('loadedmetadata', ...)作为起点,此时video.textTracks已初始化(但可能还未加载完 vtt) - 对每个
TextTrack实例监听onload和onerror:只有对应的TextTrack对象才支持这两个事件,且仅在src加载完成或失败时触发 - 用
video.textTracks.onaddtrack捕获动态插入的track元素(例如通过video.addTextTrack()或 JS 创建后 append)
示例:
const video = document.querySelector('video');
video.textTracks.onaddtrack = (e) => {
const track = e.track;
console.log(`track added: ${track.kind} (${track.srclang})`);
track.onload = () => console.log('vtt loaded');
track.onerror = () => console.error('vtt load failed');
};
// 初始 tracks 在 loadedmetadata 后可用
video.addEventListener('loadedmetadata', () => {
for (const track of video.textTracks) {
// 补监听已存在的 track
if (!track.onload) track.onload = () => console.log('existing track loaded');
}
});
如何检测用户手动切换字幕语言(mode 变更)
TextTrack.mode 变更没有原生事件,唯一可行方案是轮询——但必须极轻量、有节制:
从零开始创建惊艳、动画丰富且自包含的 HTML 演示文稿,或通过转换 PowerPoint 文件生成。当用户希望制作幻灯片、构建演示文稿、打造路演资料(pitch deck)、将 PPT/PPTX 转换为网页格式,或增强现有 HTML 演示文稿时,应使用此能力。该能力帮助用户通过视觉预览而非抽象选项来发掘自身审美偏好。
- 不要 setInterval,改用
requestIdleCallback或每 200ms 检查一次video.textTracks中所有 track 的mode - 只比对
mode值变化,忽略readyState波动(它常为 0 或 2,与显示无关) - 过滤掉未启用的 track:
track.mode !== 'disabled'才值得记录 - 注意 Safari 行为:用户关闭字幕菜单后,所有 track.mode 会变成
'disabled',但 Chrome 可能保留最后一个选中的为'showing'
简单轮询逻辑:
let lastModes = new WeakMap();
function checkTrackModes() {
for (const track of video.textTracks) {
const current = track.mode;
const prev = lastModes.get(track) || '';
if (current !== prev && current !== 'disabled') {
console.log(`track language switched to: ${track.srclang}`);
lastModes.set(track, current);
}
}
}
// 启动(实际项目中加防抖和停止机制)
setInterval(checkTrackModes, 200);
data-track 属性对 track 元素无效,别白费力气
track 是 void 元素,不参与交互流,也不冒泡事件。给它加 data-track="subtitles_zh" 并监听 click/pointerdown 完全没意义——没人会直接点击 标签。
- 埋点应放在用户可操作的控件上:比如自定义字幕开关按钮、语言选择下拉框
- 若需关联到具体
track,在按钮点击时读取目标track的srclang或label,而非依赖其自身属性 - 试图用
document.addEventListener('click', e => e.target.closest('track'))永远得不到结果,因为track不渲染为任何可见节点
真正容易被忽略的是:所有 track 相关状态变更都发生在 TextTrack 对象层面,而不是 HTML 元素本身。盯着 标签写监听逻辑,从起点就错了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










