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

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

4

2 回答 2

11

几个问题(从大到小):

  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函数的节点抛出异常,并且它将丢失具有多个类的元素。例如:<p class="foo nav bar">...

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

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

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

  6. 此信息适用于 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');
        }
    }
}
于 2013-07-13T23:51:34.920 回答
0

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

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

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

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

于 2013-07-13T17:32:49.103 回答