应使用 MutationObserver 监听动态插入的 video 元素,通过 childList 和 subtree 选项捕获新增节点,结合 instanceof HTMLVideoElement 或 querySelectorAll 精准识别,并用 data-watched 标记去重;可封装为 watchVideos 函数并支持 IntersectionObserver 实现视口内触发。

直接用 querySelector 无法监听动态插入的元素,它只查当前 DOM 快照。要“优雅”响应新视频标签(比如由框架、懒加载或用户操作插入),关键不是反复轮询,而是结合 MutationObserver 主动感知变化,并精准过滤 <video></video> 标签。
用 MutationObserver 监听新增的 video 元素
MutationObserver 是现代浏览器推荐的、高效且低开销的方式,它能监听 DOM 变化并只在真正插入时触发。
- 观察整个
document.body或某个容器节点,设置childList: true和subtree: true覆盖深层插入 - 在回调中遍历
mutation.addedNodes,用node instanceof HTMLVideoElement或node.tagName === 'VIDEO'精准识别新视频 - 避免重复处理:可给已处理过的
<video></video>打标记(如data-handled="true"),或用Set缓存其引用
封装成可复用的 watchVideos 函数
把逻辑收拢,支持传入自定义回调,便于在不同场景复用:
function watchVideos(callback) {
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node instanceof HTMLVideoElement && !node.hasAttribute('data-watched')) {
node.setAttribute('data-watched', 'true');
callback(node);
}
// 也检查子节点(比如插入的是包含 video 的 div)
if (node.querySelectorAll) {
node.querySelectorAll('video:not([data-watched])').forEach(v => {
v.setAttribute('data-watched', 'true');
callback(v);
});
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
return () => observer.disconnect();
}
使用时只需:watchVideos(video => console.log('新视频来了:', video)),简洁清晰。
配合 IntersectionObserver 实现“可见即处理”
如果业务只需处理进入视口的视频(如自动播放、打点埋点),可叠加 IntersectionObserver,避免过早干预未展示的 video:
- 在
watchVideos回调里为新 video 创建一个IntersectionObserver实例 - 首次进入视口时执行初始化逻辑(如绑定事件、加载封面、上报曝光)
- 注意:单个 observer 可监听多个目标,别为每个 video 都新建 observer,应复用
避开常见坑
实际项目中容易踩的点:
- 不要用 setInterval + querySelectorAll:性能差、有延迟、可能漏掉瞬间插入又移除的 video
- 避免监听 document.documentElement:某些框架(如 Vue)会在 head 插入 style,导致无意义触发;body 更稳妥
- 注意 Shadow DOM:若视频在自定义组件的 shadow root 中,需单独观察对应 root,MutationObserver 默认不穿透
-
兼容性兜底:IE 不支持 MutationObserver,如需兼容,可用
DOMNodeInserted(已废弃但 IE 支持),或改用框架生命周期钩子(如 Vue 的mounted)
不复杂但容易忽略——核心是放弃“主动查”,转向“被动通知”。MutationObserver + 精准过滤 + 合理缓存,就能干净利落地接管所有动态视频。

















