小编典典

如何使用Tampermonkey脚本替换AJAX驱动的页面文本和选择属性中的大量单词?

ajax

我正在使用树浏览器仅影响文本节点来翻译HTML文档中的文本/单词/术语:

var replaceArry = [
    [/View your user account/gi,    'Tu cuenta'],
    // etc.
];
var numTerms    = replaceArry.length;
var txtWalker   = document.createTreeWalker (
    document.body,
    NodeFilter.SHOW_TEXT,
    {   acceptNode: function (node) {
            //-- Skip whitespace-only nodes
            if (node.nodeValue.trim() )
                return NodeFilter.FILTER_ACCEPT;

            return NodeFilter.FILTER_SKIP;
        }
    },
    false
);

var txtNode     = null;
while (txtNode  = txtWalker.nextNode () ) {
    var oldTxt  = txtNode.nodeValue;

    for (var J  = 0;  J < numTerms;  J++) {
        oldTxt  = oldTxt.replace (replaceArry[J][0], replaceArry[J][1]);
    }
    txtNode.nodeValue = oldTxt;
}

这在静态页面上效果很好(并且不会破坏超链接或事件处理程序),但我还希望它:

  • 捕获AJAX内容
  • 替换placeholder属性中的文本

阅读 597

收藏
2020-07-26

共1个答案

小编典典

要处理AJAX内容,可以使用MutationObservers或使用计时器进行轮询。前者会变得棘手和复杂,而计时器则简单,健壮,并且对于大多数实际应用都适用。

要处理类似的属性placeholder,只需使用document.querySelectorAll("[placeholder]")获取节点并遍历生成的
NodeList即可

当您使用它时,您可能还需要转换title属性。

简而言之:

  • 将替换代码放入函数中。
  • 在中调用该函数setInterval
  • 在间隔内,为要更改的属性添加一个单独的循环。

放在一起,跨浏览器用户脚本将如下所示。查看内联注释,
您可以 针对 此jsFiddle页面测试脚本。

// ==UserScript==
// @name     Replace lots of terms on an AJAX'd page
// @include  http://fiddle.jshell.net/Hp6K2/show/*
// @grant    none
// ==/UserScript==
var replaceArry = [
    [/text/gi,                      'blather'],
    [/View your user account/gi,    'Tu cuenta'],
    // etc.
];
var numTerms    = replaceArry.length;
                  //-- 5 times/second; Plenty fast.
var transTimer  = setInterval (translateTermsOnPage, 222);

function translateTermsOnPage () {
    /*--- Replace text on the page without busting links or javascript 
        functionality.
    */
    var txtWalker   = document.createTreeWalker (
        document.body,
        NodeFilter.SHOW_TEXT, {
            acceptNode: function (node) {
                //-- Skip whitespace-only nodes
                if (node.nodeValue.trim() ) {
                    if (node.tmWasProcessed)
                        return NodeFilter.FILTER_SKIP;
                    else
                        return NodeFilter.FILTER_ACCEPT;
                }
                return NodeFilter.FILTER_SKIP;
            }
        },
        false
    );
    var txtNode     = null;
    while (txtNode  = txtWalker.nextNode () ) {
        txtNode.nodeValue       = replaceAllTerms (txtNode.nodeValue);
        txtNode.tmWasProcessed  = true;
    }
    //
    //--- Now replace user-visible attributes.
    //
    var placeholderNodes    = document.querySelectorAll ("[placeholder]");
    replaceManyAttributeTexts (placeholderNodes, "placeholder");

    var titleNodes          = document.querySelectorAll ("[title]");
    replaceManyAttributeTexts (titleNodes, "title");
}

function replaceAllTerms (oldTxt) {
    for (var J  = 0;  J < numTerms;  J++) {
        oldTxt  = oldTxt.replace (replaceArry[J][0], replaceArry[J][1]);
    }
    return oldTxt;
}

function replaceManyAttributeTexts (nodeList, attributeName) {
    for (var J = nodeList.length - 1;  J >= 0;  --J) {
        var node    = nodeList[J];
        var oldText = node.getAttribute (attributeName);
        if (oldText) {
            oldText = replaceAllTerms (oldText);
            node.setAttribute (attributeName, oldText);
        }
        else
            throw "attributeName does not match nodeList in replaceManyAttributeTexts";
    }
}
2020-07-26