MutationObserver error : How could I wait for the creation of an element?

MutationObserver error : How could I wait for the creation of an element?

我正在尝试制作 Greasemonkey 脚本以在 Facebook 页面中添加按钮。 但我需要等待创建一个元素才能在其上添加按钮。
我正在尝试使用 MutationObserver (As suggested here) 来执行此操作,但出现错误。

function init() {
    console.log('Launched : ' + launched);
    if (!launched) {
        launched = true;
        main();
    }
}
console.log('barfoo');

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        if (!mutation.addedNodes) return;
        console.log(mutation.addedNodes.type());
        for (var i = 0; i < mutation.addedNodes.length; i++) {
            if (mutation.addedNodes[i].matches('div[class="pam _5shk uiBoxWhite bottomborder"]')) {
                console.log('init');
                init();
            }
        }
    })
});
console.log('bar');

try {
    observer.observe(document.body, {
        childlist: true,
        subtree: true,
        attributes: false,
        characterData: false,
    });
} catch (error) {
    console.log(error);
}
console.log('foobar');

但是我得到了以下日志:

barfoo
bar
DOMException [TypeError: "The expression cannot be converted to return the specified type."
code: 0
nsresult: 0x805b0034
location: file:///home/vmonteco/.mozilla/firefox/f3xgmo8e.default/gm_scripts/Facebook_cleaner/Facebook_cleaner.user.js:230] Facebook_cleaner.user.js:239:3
foobar

这个错误的原因是什么? 我该如何解决这个问题?

如果元素是在我的脚本执行之前创建的,MutationObserver 是否仍会被触发? (IE,如果我创建 MutationObserver 时该元素已经存在)。

注意: 我尝试使用 $(document).ready(),但它是在我要添加按钮的元素创建之前触发的。

NB-bis:我没有post整个脚本。

不幸的是,该错误消息使用起来非常模糊,但您打错了字:

observer.observe(document.body, {
  childlist: true,
  subtree: true,
  attributes: false,
  characterData: false,
});

应该是

observer.observe(document.body, {
  childList: true,
  subtree: true,
  attributes: false,
  characterData: false,
});

例如childlist => childList

在这种情况下,运行 您在 Chrome 中的相同代码比 "cannot be converted to return the specified type" 提供了更有用的信息。它说

The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.

实际上,MutationObserver不是最好的方法(因为你正在艰难地学习。它很快就会变得复杂和脆弱。它真的可以陷入困境下一个网页,跨平台不一致)。
此外,如果该元素在您的脚本触发之前就存在,MutationObserver 将不会捕获它。

使用如 Run Greasemonkey script on the same page, multiple times? 所示的方法。

这样,你的整个脚本就变成了:

// ==UserScript==
// @name     _Wait for specific divs
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @require  http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/
waitForKeyElements (
    'div.pam _5shk.uiBoxWhite.bottomborder', processDiv
);

function processDiv (jNode) {
    //  YOUR CODE HERE.
    // For example:
    jNode.css ("background", "pink");
}

看看这有多简单! :)
使用 waitForKeyElements() 您可以根据需要使用任何复杂的 jQuery 选择器。


如果您真的坚持 MutationObservers,请使用可以减轻很多痛苦的库。

我看到有人认为 Mu​​tationObserver 不是执行此操作的方法,但实际上它是。细微差别是,如果您想处理从一开始就加载的页面节点,那么为了不遗漏任何内容,您必须 运行 具有 // @run-at document-start 条件的 Monkey 脚本,然后附加观察者到 document.documentElement 以捕获所有内容(或者如果您确定稍后页面中的非内容会发生变化会破坏此内容,则到后来出现的元素):

(function()
{
  new MutationObserver((mutationsList, observer) => { 
    for (let mutation of mutationsList)
    {
      if (mutation.type != 'childList' || !mutation.addedNodes.length)
      {
        continue;
      } 
      Array.from(mutation.addedNodes).forEach(function(e) // or forSome if you only want to catch one object such as a button
      {
        if (!(e instanceof Element))
        {
          return;
        }
        // do stuff
      });  
    }
  }).observe(document.documentElement, {childList: true, subtree: true});
})();