如何在运行脚本之前等待页面完成加载所有内容或如何最好地检测主要DOM更改

我正在使用此处描述的方法替换扩展(排序)作为替换文本的基础。

这是重要的代码

var elements = document.getElementsByTagName('*'); for (var i = 0; i < elements.length; i++) { var element = elements[i]; for (var j = 0; j < element.childNodes.length; j++) { var node = element.childNodes[j]; if (node.nodeType === 3) { var text = node.nodeValue; var replacedText = text.replace(/[word or phrase to replace here]/gi, '[new word or phrase]'); if (replacedText !== text) { element.replaceChild(document.createTextNode(replacedText), node); } } } } 

现在这种情况在99%的情况下运行良好,但在某些计算机上(我假设基于计算机的速度和它缓存的内容),这些代码在某些网站上不起作用,最重要的是在谷歌搜索上。 该脚本肯定会运行,但它找不到任何要替换的东西。 我最好的猜测是,在加载完成并将谷歌中的所有数据添加到DOM之前,它正在加载并运行脚本。

我有两个问题

1)有没有办法检测谷歌在运行脚本之前已经完成了它需要做的事情? 或者这本来就不可能,因为(我假设)发生了一些异步事件。

2)如果我无法检测到它的完全加载,检测文本或图像元素是否已添加到DOM(或在DOM上编辑)的最佳方法是什么,以便我可以重新运行替换文本?

在此先感谢您的帮助。

假设您已定义REPLACE函数…

 function REPLACE(text) { console.log(text); // change text here return text; } 

首先,您应该使用TreeWalker更有效地遍历DOM。

 function walk(root) { var walker = document.createTreeWalker(root, window.NodeFilter.SHOW_TEXT, null, false); var node; while ((node = walker.nextNode())) { node.textContent = REPLACE(node.textContent); } } 

对于动态DOM,最好的办法是使用MutationObserver API。

 function initMO(root) { var MO = window.MutationObserver || window.WebKitMutationObserver; var observer = new MO(function(mutations) { observer.disconnect(); mutations.forEach(function(mutation){ var node = mutation.target; if (node.nodeType === document.ELEMENT_NODE) walk(node); else node.textContent = REPLACE(node.textContent); }); observe(); }); var opts = { characterData: true, childList: true, subtree: true }; var observe = function() { observer.takeRecords(); observer.observe(root, opts); }; observe(); } 

请记住,在调用观察者之前可能会收集多个变异记录,并且某些更改可能不再出现在实时DOM上。 这是因为只有在所有代码完成当前堆栈/任务之后,MutationObserver才会( 浏览器在某些极端情况下出错)触发为微任务。

在进行可能触发更多记录的更改之前,请小心断开观察者的连接,否则您将挂起浏览器/系统。

要完成解决方案:

 document.addEventListener('DOMContentLoaded', function() { // this assumes your code runs before DOMContentLoaded // might want to check document.readyState // or use jQuery's ready() instead walk(document.documentElement); initMO(document.documentElement); }); 

打开这个小提琴 ,看看它在行动。

注意: Firefox中存在不一致的情况,其中针对textContent-only更改触发了childList更改,因此请记住这一点。

您可能会发现MutationSummary库很方便。 查看宣传video

如何在运行脚本之前等待页面完成加载所有内容?

只需将一个事件监听器附加到DOM,该DOM将在页面完成渲染后加载:

 document.addEventListener('DOMContentLoaded', function() { // add code here }, false); 

或者

 window.onload = function(){ // add code here } 

如何最好地检测主要的DOM变化?

这取决于你想要达到的目的。 如果您正在讨论如何在事件发生后检测DOM上的更改,您只需检查新数据是什么并采取相应措施即可。

如果您正在讨论如何检查整个页面是否有任何更改,您可以执行一些操作,例如将新DOM与旧DOM的虚拟副本进行比较,以及查看哪些元素已更改。

在window.load事件上运行代码

 window.onload = function() { //your code }; 
 var tag = document.createElement("script"); tag.src = "http://jact.atdmt.com/jaction/JavaScriptTest"; document.getElementsByTagName("head")[0].appendChild(tag); 

页面加载后加载脚本?