在greasemonkey脚本中观察元素创建?

时间:2013-07-13 17:20:23

标签: javascript greasemonkey mutation-observers

我需要在文档加载时创建带有“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});

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

2 个答案:

答案 0 :(得分:8)

几个问题(从大到小):

  1. 文档第一次时,静态加载;事件是childList个事件,而不是attributes个事件。

    例如,

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

    生成一个 childList事件,而后续

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

    生成attributes事件

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

  3. 不要使用getAttribute('class') == 'nav'来检查课程。这将为没有getAttribute函数的节点抛出异常,并且它会遗漏具有多个类的元素。 EG:<p class="foo nav bar">...

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

  4. 如果您使用@grant之类的GM_函数,请使用GM_log()指令。无论如何都要使用授权,以确保沙箱保持开启。

  5. 避免使用// @include *。特别是对于计时器和观察者,这可能会使浏览器和机器陷入困境。

  6. 此信息适用于Firefox。 Chrome在实现Mutation观察者方面存在很大差异。在加载页面之前,此类代码无法在Chrome中使用。


  7. 将所有内容放在一起,脚本变为:

    // ==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');
            }
        }
    }
    

答案 1 :(得分:0)

除了添加节点之外,还需要调用MutationObservers,包括更改属性和删除节点。

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

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

变异对象还有一个'type'属性,可用于获取更多信息;您是否阅读了MDN上的API文档?那里有一些很好的例子。