首页 > 解决方案 > 如何在不先加载原始文本的情况下替换网页上的文本?

问题描述

我正在尝试为浏览器扩展找到正确的 JavaScript 代码,将网页文本中的“冬季”一词替换为“夏季”一词。

第一次尝试

根据这篇博文,我的第一次尝试是

function wordFilter() {

    let target = "winter";
    let replace = "summer";

    var html = document.querySelector('html');
    var walker = document.createTreeWalker(html, NodeFilter.SHOW_TEXT);
    var node;
    while (node = walker.nextNode()) {
        node.nodeValue = node.nodeValue.replace(target, replace);
    }
}

wordFilter()

这几乎可以工作。它确实将“冬天”替换为“夏天”,但“冬天”这个词在被替换之前仍会出现在屏幕上几秒钟。我希望过滤器从一开始就起作用。

至少,这个尝试表明我的一般扩展设置权限是正确的,所以任何进一步的失败都必须是代码问题。

第二次尝试

我的第二次尝试是基于对StackOverflow 帖子的这个答案。这是一个涉及的帖子,但“添加节点的朴素枚举”下的部分最接近我想要的。函数中的代码onMutation()搜索<h1>包含目标文本的元素;只是为了概念验证,我简化了这部分代码以应用于作为添加元素的后代的所有元素。如果初始 DOM 加载符合一组 Mutations (我仍然不清楚,但从似乎是预期行为的上下文中),那么这应该捕获页面上的每个元素和每段文本。

编码:

var observer = new MutationObserver(onMutation);
observer.observe(document, {
    childList: true, // report added/removed nodes
    subtree: true,   // observe any descendant elements
});

function onMutation(mutations, observer) {
    for (var i = 0, len = mutations.length; i < len; i++) {
        var added = mutations[i].addedNodes;
        for (var j = 0, node; (node = added[j]); j++) {
            replaceText(node);  
        }
    }
}

function replaceText(el) {
    let target_string = "winter";
    let replacement_string = "summer";

    const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
    for (let node; (node = walker.nextNode());) {
        const text = node.nodeValue;
        const newText = text.replace(target_string, replacement_string);
        if (text !== newText) {
            node.nodeValue = newText;
        }
    }
}

这根本不起作用。在任何情况下,任何时候都不会用任何东西代替“冬天”这个词的任何实例。

现在我不知所措了。如何替换网页上的文本而不在替换之前出现原始文本?

标签: javascriptbrowser-extension

解决方案


我可以确认wOxxOm 选择的方法(在我的帖子中链接)运行良好,包括我尝试使用的方法。

这种情况下的问题是浏览器插入代码的时间。

manifest.json允许一个"content_scripts""run_at"指定浏览器何时应该加载内容脚本(更多内容见MDN)。默认值为"document_idle",这似乎意味着“只要有机会”。

使用此默认设置,浏览器正在加载页面,然后等待直到它有空闲时刻加载扩展脚本以开始查找 Mutations。因此,MutationObserver 错过了所有初始突变,脚本似乎无法正常工作。(顺便说一句:我现在确信每个 DOM 元素的初始加载确实算作DOM的突变)。

通过"run_at": "document_start"manifest.json这样指定:

"content_scripts": [
    {
        "js": ["filename.js"],
        "run_at": "document_start"
    }
]

浏览器在开始加载 DOM 时立即运行脚本来监视 Mutations,因此会捕获初始的 Mutations,并且在加载之前更改文本,以便原始的“冬天”在更改为“之前不会出现在页面上”夏天”。

特别感谢@Jason Goemaat 的提示。


推荐阅读