如何使用MutationObserver检测脚本是否已加载?
解决脚本加载检测问题(兼容已加载状态)
首先明确:MutationObserver本身不直接监听脚本的onload事件,但可以结合脚本的readyState属性,实现「不管脚本是已加载完成,还是后续插入DOM」都能触发回调的需求,同时替换掉废弃的DOMNodeInserted事件,解决控制台警告。
实现思路与步骤
- 先检查已存在的脚本:查询目标脚本,若已存在则判断其加载状态——若已加载(
readyState为loaded或complete),直接执行回调;若未加载,添加load事件监听。 - 用MutationObserver监听脚本插入:监听整个文档的元素插入操作,当匹配到目标src的脚本时,重复第一步的判断逻辑。
- 避免重复触发:给已处理过的脚本标记自定义属性,防止同一脚本多次触发回调。
- 清理资源:在Lit元素断开DOM时,断开观察者避免内存泄漏。
适配Lit Element的完整代码
// 在组件类中添加属性 private disconnectObserver?: () => void; connectedCallback() { super.connectedCallback(); const targetSrc = highlightCore(); // 定义脚本加载完成后的处理逻辑 const handleScriptLoad = (script: HTMLScriptElement) => { console.log(`Highlighter.js script loaded`); console.log('Script loaded: ' + script.getAttribute('src')); // 这里添加你的业务逻辑 script.dataset.processed = 'true'; // 标记已处理,避免重复触发 }; // 1. 检查页面中已存在的目标脚本 const existingScript = document.querySelector(`script[src="${targetSrc}"]`); if (existingScript) { if (existingScript.dataset.processed) return; // 判断脚本是否已加载完成 if (existingScript.readyState === 'loaded' || existingScript.readyState === 'complete') { handleScriptLoad(existingScript); } else { existingScript.addEventListener('load', () => handleScriptLoad(existingScript)); } } // 2. 初始化MutationObserver监听新插入的脚本 const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeName === 'SCRIPT' && (node as HTMLScriptElement).src === targetSrc) { const script = node as HTMLScriptElement; if (script.dataset.processed) return; if (script.readyState === 'loaded' || script.readyState === 'complete') { handleScriptLoad(script); } else { script.addEventListener('load', () => handleScriptLoad(script)); } } }); }); }); // 配置监听规则:监听整个文档树的元素插入 observer.observe(document.documentElement, { childList: true, subtree: true }); // 保存断开观察者的方法,用于组件销毁时清理 this.disconnectObserver = () => observer.disconnect(); } disconnectedCallback() { super.disconnectedCallback(); // 组件从DOM移除时,断开观察者防止内存泄漏 if (this.disconnectObserver) { this.disconnectObserver(); } }
关键细节说明
- 兼容已加载脚本:脚本加载完成后,
readyState会变为loaded或complete(不同浏览器表现略有差异,需同时判断),此时无需等待load事件,直接执行回调。 - 替换废弃事件:用MutationObserver的
childList+subtree监听,完全替代DOMNodeInserted,解决控制台的 deprecation 警告。 - 避免重复触发:通过自定义
data-processed属性标记已处理的脚本,确保同一脚本不会多次触发回调逻辑。 - 内存泄漏防护:在
disconnectedCallback中主动断开观察者,符合Lit组件的生命周期规范。
内容的提问来源于stack exchange,提问作者Ole
相关产品推荐
相关产品推荐

