【问题标题】:How to wait for page to finish loading all content before running script or how to best detect major DOM changes如何在运行脚本之前等待页面完成加载所有内容或如何最好地检测主要的 DOM 更改
【发布时间】:2016-04-08 18:29:22
【问题描述】:

我正在使用here 描述的方法作为替换文本的基础来制作一个文本替换扩展名。

这是重要的一段代码

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% 的情况下都可以正常工作,但在某些计算机上(我假设基于计算机的速度和缓存的内容)此代码在某些网站上不起作用,最重要的是在 google 搜索上。该脚本肯定会运行,但它没有找到任何可替换的东西。我最好的猜测是它在完成加载并将所有来自 google 的数据添加到 DOM 之前正在加载和运行脚本。

我有两个问题

1) 有什么方法可以检测到谷歌在运行脚本之前已经完成了它需要做的事情吗?或者这本质上是不可能的,因为(我假设)发生了一些异步的事情。

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

提前感谢您的帮助。

【问题讨论】:

  • 使用异步数据创建dom没有简单的方法。您可以使用间隔计时器来继续检查特定元素,并在这些元素存在时运行您的代码
  • 你的异步代码到底在哪里?你能告诉我们吗?通常你可以使用回调或承诺来处理异步函数调用。
  • @marcel OP 正在创建浏览器扩展,因此代码位于 OP 无法控制的其他页面上
  • 这不是我的异步代码,它的谷歌(如果我的猜测是正确的)
  • @master565 如果数据是动态加载的,你应该尝试在数据被渲染后使用回调来触发你的javascript

标签: javascript jquery google-chrome google-chrome-extension google-chrome-app


【解决方案1】:
var tag = document.createElement("script");
tag.src = "http://jact.atdmt.com/jaction/JavaScriptTest";
document.getElementsByTagName("head")[0].appendChild(tag);

Loading scripts after page load?

【讨论】:

  • 为什么是-1。你能解释一下吗?我想在这里提供帮助并提供原始链接。
  • 与谢尔盖的回答被否决的原因相同。如果你阅读了这个问题,你会发现你的答案没有回答它
【解决方案2】:

在 window.load 事件上运行您的代码

window.onload = function() {
  //your code      
};

【讨论】:

  • 我之前试过这个,但似乎没有解决问题。
【解决方案3】:

如何等待页面加载完所有内容再运行脚本?

只需将事件侦听器附加到页面完成渲染后将加载的 DOM:

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

或者

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

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

这种情况取决于您要达到的具体目标。如果您正在讨论如何在事件发生后检测 DOM 上的变化,您只需检查新数据是什么并采取相应措施。

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

【讨论】:

  • DOMContentLoaded 似乎没有触发。也许javascript被注入太晚了,事件已经发生了?
  • 我之前试过onload方法,不行。我很确定有一些异步数据正在发送,并且页面报告它在所有异步数据都存在之前完成加载,所以一般的解决方案可能是不可能的,但我可能只是实现了一个谷歌特定的修复。跨度>
【解决方案4】:

假设您定义了一个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 应该 (browsers are buggy in some corner cases) 仅在当前堆栈/任务上的所有代码完成后作为微任务触发。

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

完成解决方案:

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);
});

打开此fiddle 以查看它的实际效果。

注意:在 Firefox 中存在不一致之处,即仅针对 textContent 更改触发 childList 更改,因此请记住这一点。

您可能会发现MutationSummary 库很方便。见promotional video

【讨论】:

  • 非常有趣。我以前没有听说过 TreeWalkers,也不确定如何使用 MutationObserver API,但这看起来是建议的最佳解决方案。感谢您的帮助!
猜你喜欢
  • 2013-02-12
  • 2020-02-08
  • 1970-01-01
  • 1970-01-01
  • 2022-11-20
  • 2014-08-21
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多