chrome 新段落文本的 MutationObserver

chrome MutationObserver for new paragraph text

我还没有真正理解如何使用 mutationObserver,但我目前拥有的似乎有些正确......我想在代码中每次出现新的 p 标记时执行一个操作.. 到目前为止,这是我的代码:

var target = $('p');
var observer = new WebKitMutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        chrome.storage.sync.get({ getInjection: true }, function(getInject) {
        var getInjectionState = getInject.getInjection;
        if(getInjectionState == true) {
                arrayOfP = $("p").text();
                chrome.runtime.sendMessage(arrayOfP, manageResponse);
            }
        });
    });    
});
observer.observe(target[0], { attributes: true, childList: true, characterData: true });

此代码位于 chrome 扩展的内容脚本中。为什么它不起作用?任何帮助,将不胜感激。谢谢!

  1. observer.observe 应该观察添加了新 p 元素的 parent/container 元素或 document.body.

    • observer.observe($('.some-container-selector')[0], .....
    • observer.observe(document.body, .....
  2. 在回调中你应该检查添加的节点是否实际上是 p:

    mutations.forEach(function(mutation) {
      Array.prototype.forEach.call(mutation.addedNodes, function(node) {
        if (node.nodeType != 1) return; // only process Node.ELEMENT_NODE
        if (node.localName != 'p') { // not P but might be DIV with P inside
          node = node.querySelector('p');
          if (!node) return;
        }
        // now we have our P node
        console.log("Got P!", node);
      });
    });
    


作为替代,这里有一个我重复使用了几年的函数,它有一个更丑陋但更快的 for 循环:

function setMutationHandler(baseNode, selector, cb) {
  new MutationObserver(function(mutations) {
    for (var i=0, ml=mutations.length, m; (i<ml) && (m=mutations[i]); i++)
      for (var j=0, nodes=m.addedNodes, nl=nodes.length, n; (j<nl) && (n=nodes[j]); j++)
        if (n.nodeType == 1) 
          if ((n = n.matches(selector) ? [n] : n.querySelectorAll(selector)) && n.length)
            if (!cb.call(this, [].slice.call(n)))
              return;
  }).observe(baseNode, {subtree:true, childList:true}); 
}

用法(这里的回调将仅接收 .some-container-class 下的 p 个元素):

setMutationHandler(document, '.some-container-class p', function(nodes) {
  nodes.forEach(function(node) {
    console.log("Got node", node);
    // do something
  });
  //this.disconnect(); // disconnect the observer, useful for one-time jobs
  //return true; // continue enumerating current batch of mutations
});

与 setMutationHandler 的循环相比,最后一个 for 循环很少出现,因此它可能会被更简洁的 [].forEach.call(nodes, ...Array.prototype.forEach.call(nodes, .... 或 jQuery 包装器替换为 .each.

P.P.S。对于 Chrome pre-34,这需要在脚本开头的某处:

if (!Element.prototype.matches)
    Element.prototype.matches = Element.prototype.webkitMatchesSelector;