注意在greasemonkey 脚本中创建元素?

Posted

技术标签:

【中文标题】注意在greasemonkey 脚本中创建元素?【英文标题】:Watch for element creation in greasemonkey script? 【发布时间】:2013-07-12 00:47:10 【问题描述】:

当文档加载时创建了“nav”类的元素时,我需要得到通知。谷歌搜索我找到了 MutationObservers 并认为它们会很完美,但我似乎无法让它工作。

// ==UserScript==
// @name        ii-shortcuts
// @namespace   https://github.com/RedHatter
// @include     *
// @version     1
// @run-at document-start
// ==/UserScript==

var observer = new MutationObserver(function(mutations)

    mutations.forEach(function(mutation)
    
        if (mutation.target.getAttribute('class') == 'nav')
            GM_log('nav creation');
    );    
);
observer.observe(document, subtree: true, attributes: true, attributeFilter: ['class']);    

我也试过了。

// ==UserScript==
// @name        ii-shortcuts
// @namespace   https://github.com/RedHatter
// @include     *
// @version     1
// @run-at document-start
// ==/UserScript==

var observer = new MutationObserver(function(mutations)

    mutations.forEach(function(mutation)
    
        if (mutation.addedNodes[0].getAttribute('class') == 'nav')
            GM_log('nav creation');
    );    
);
observer.observe(document, subtree: true, childList: true);

但在下一种情况下是“导航创建”登录页面加载。我错过了什么?

【问题讨论】:

@CrazyTrain Not accouding to the specs "DOM 突变事件不能因为 UA 解析文档引起的变化而触发……但是,根据 DOM 规范的要求,突变观察者会触发。 " 你可以使用arrive.js,它提供了很好的简单api来监听元素的创建(内部使用MutationObserver) 嗯...看起来很不错。谢谢@UzairFarooq 【参考方案1】:

几个问题(从大到小):

    当文档第一次加载时,静态加载;这些事件是childList 事件,而不是attributes 事件。

    例如,

    $("body").append ('<p id="foo" class="bar">Hiya!</p><p>blah</p>');
    

    生成 一个 childList 事件,而随后的

    $("#foo").attr ("class", "bar2");
    

    生成attributes 事件。

    mutation.addedNodes[0] 包含类 nav 的元素的几率几乎为零。这几乎总是一个文本节点。 您需要检查整个数组,加上target

    不要使用getAttribute('class') == 'nav' 来检查课程。这将为没有getAttribute 函数的节点抛出异常,并且它会丢失具有多个类的元素。例如:&lt;p class="foo nav bar"&gt;...

    在适当的节点类型上使用classList.contains()

    如果您使用任何GM_ 函数(如GM_log()),请使用@grant 指令。无论如何都要使用授权,以确保沙盒保持打开状态。

    避免使用// @include *。尤其是对于计时器和观察者,这可能会使您的浏览器和您的机器陷入瘫痪。

    此信息适用于 Firefox。 Chrome 在实现 Mutation 观察者的方式上存在很大差异。此类代码在页面加载前无法在 Chrome 中运行。


把它们放在一起,脚本变成:

// ==UserScript==
// @name        _ii-shortcuts
// @namespace   https://github.com/RedHatter
// @include     http://YOUR_SERVER.COM/YOUR_PATH/*
// @run-at      document-start
// @version     1
// @grant       GM_log
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/
var MutationObserver = window.MutationObserver;
var myObserver       = new MutationObserver (mutationHandler);
var obsConfig        = 
    childList: true, attributes: true,
    subtree: true,   attributeFilter: ['class']
;

myObserver.observe (document, obsConfig);

function mutationHandler (mutationRecords) 

    mutationRecords.forEach ( function (mutation) 

        if (    mutation.type               == "childList"
            &&  typeof mutation.addedNodes  == "object"
            &&  mutation.addedNodes.length
        ) 
            for (var J = 0, L = mutation.addedNodes.length;  J < L;  ++J) 
                checkForCSS_Class (mutation.addedNodes[J], "nav");
            
        
        else if (mutation.type == "attributes") 
            checkForCSS_Class (mutation.target, "nav");
        
     );


function checkForCSS_Class (node, className) 
    //-- Only process element nodes
    if (node.nodeType === 1) 
        if (node.classList.contains (className) ) 
            console.log (
                'New node with class "' + className + '" = ', node
            );
            // YOUR CODE HERE
            //GM_log ('nav creation');
        
    

【讨论】:

感谢您的提示!虽然我打算在脚本完成后添加一个@grant(否则你会得到那个烦人的弹出),我只放了@include *,因为我不想显示我在哪个网站上使用脚本。 【参考方案2】:

调用 MutationObservers 的目的不仅仅是添加节点,包括更改属性和删除节点。

因此请注意 mutation.addedNodes 返回 null - 在这种情况下,此代码将失败。试试:

if (mutation.addedNodes && mutation.addedNodes[0].getAttribute('class') === 'nav') 
  ...

突变对象还有一个“类型”属性,您可以使用它来获取更多信息;你读过MDN 上的API 文档吗?那里有一些很好的例子。

【讨论】:

我尝试了代码,并没有改变任何东西。问题不是脚本失败,而是具有类 nav 的元素永远不会传递给 MutationObserver。是的,我已经阅读了文档。 您是否有一个测试页面,其中包含您正在使用此代码观看的 html

以上是关于注意在greasemonkey 脚本中创建元素?的主要内容,如果未能解决你的问题,请参考以下文章

包括跨多个域的 Greasemonkey 脚本

如何在 Google Chrome 的 Greasemonkey 脚本中使用 jQuery?

将 Greasemonkey/Tampermonkey 用户脚本应用到 iframe

使用异常内容加载时不执行 Greasemonkey 脚本

Greasemonkey脚本中的setinterval()和.click()[重复]

在 Firefox、Greasemonkey 脚本中使用时,console.log 不起作用