track元素不能用innerHTML清空,因其是video/audio的伪子节点而非真实DOM子节点;正确删除需querySelectorAll('track').forEach(t=>t.remove())或反向遍历getElementsByTagName('track')。

track元素为什么不能用 innerHTML 清空?
因为 是 或 的**子元素,但不是其 DOM 子节点**——它被浏览器视为“伪子节点”或“关联资源”,不参与常规 DOM 树遍历。直接对 video 元素执行 innerHTML = '' 或 textContent = '' 完全无效,track 依然存在。
正确删除所有 track 元素的两种方式
必须显式定位并移除 元素本身,而非清空父容器内容:
- 用
querySelectorAll('track')+remove()(推荐):const video = document.querySelector('video'); video.querySelectorAll('track').forEach(track => track.remove()); - 用
getElementsByTagName('track')配合反向循环(兼容旧浏览器):const tracks = video.getElementsByTagName('track'); while (tracks.length > 0) { tracks[0].remove(); }注意:不能正向循环 +remove(),因为HTMLCollection是实时的,删一个后索引会塌陷。
为什么 removeChild 不总好使?
常见错误是写成 video.removeChild(track) 却报错 NotFoundError。这是因为:
-
track节点的parentNode往往不是video,而是其父容器(比如div),尤其当写在外部时; - 即使
在标签内,浏览器也不保证其parentNode === video—— 实际中常为null或document。
所以优先用 track.remove(),它不依赖父节点状态,只要节点存在就能删。
动态添加后如何避免重复 track?
如果代码里反复调用 video.addTextTrack() 或插入新 标签,又没清理旧的,就会堆积。建议统一加个守卫逻辑:
// 删除已有,再添加新 track
video.querySelectorAll('track').forEach(t => t.remove());
const newTrack = video.addTextTrack('subtitles', 'zh', 'zh');
newTrack.mode = 'showing';
注意:addTextTrack() 返回的 track 对象和 DOM 中的 元素是同一个节点,所以后续也能用 querySelectorAll('track') 捕获到。
真正容易被忽略的是:某些框架(如 Vue)模板中多次渲染 标签时,DOM 可能残留上一轮未卸载的节点 —— 这时候仅靠框架 diff 不够,得在 beforeUnmount 或 disconnectedCallback 里手动清理。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











