用于创建新元素的 Mutation Observer

IT技术 javascript jquery mutation-observers dom4
2021-03-02 20:31:22

我试图在创建特定 div 时关闭一个函数。用最简单的术语来说,我有这样的事情:

<a href="" id="foo">Click me!</a>
<script>
$("#foo").live("click",function(e) {
    e.preventDefault();
    $(this).append($("<div />").html("new div").attr("id","bar"));
});
</script>

之前,我有突变事件监听 div#bar 的创建 - 像这样:

$("#bar").live("DOMNodeInserted", function(event) {
    console.log("a new div has been appended to the page");
});

是否有使用 Mutation Observers 的等价物?在 DOM 元素的样式对象更改后是否有一个 javascript 钩子触发器?但该插件仅检测元素何时被修改,而不是在创建时检测。

3个回答

这是用于侦听子列表 of 上的突变#foo并检查是否添加了具有 id 的子项的代码bar

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

$("#foo").live("click",function(e) {
    e.preventDefault();
    $(this).append($("<div />").html("new div").attr("id","bar"));
});

// define a new observer
var obs = new MutationObserver(function(mutations, observer) {
    // look through all mutations that just occured
    for(var i=0; i<mutations.length; ++i) {
        // look through all added nodes of this mutation
        for(var j=0; j<mutations[i].addedNodes.length; ++j) {
            // was a child added with ID of 'bar'?
            if(mutations[i].addedNodes[j].id == "bar") {
                console.log("bar was added!");
            }
        }
    }
});

// have the observer observe foo for changes in children
obs.observe($("#foo").get(0), {
  childList: true
});

然而,这只观察到#foo如果你想寻找#bar作为其他节点的新子节点的添加,你需要通过额外的调用来观察那些潜在的父节点obs.observe()要观察 id 为 的节点baz,您可以执行以下操作:

obs.observe($('#baz').get(0), {
  childList: true,
  subtree: true
});

添加的subtree选项意味着观察员将寻找另外的#bar无论是作为孩子更深的后裔(如孙子)。

@JimmyHa 这将适用于 Firefox 和 Webkit 浏览器。Opera 和 IE 尚不支持 Mutation Observers,因此您需要使用后备选项,例如 DOM3 突变事件(或等待很长时间以使 DOM4 方法达到实现成熟度)。
2021-05-02 20:31:22
@apsillers - 谢谢!我修改了你的 js 以适应我的需要。我不是在寻找 id,而是在寻找一个特定的类: if ($(mutations[i].addedNodes[j]).hasClass("new_div_class")) { 我只是在我的票证中说,如果用户想要我在 IE 中尝试做的相同的功能丰富的事情,他们将不得不将范围添加到项目并支付我更多。我们确定突变观察者比突变事件更好吗?似乎有更多的脚本行来做同样的事情。
2021-05-05 20:31:22
我相信观察者的主要优势是能够准确地缩小你想要的变异事件类型以及你对 DOM 的哪个部分感兴趣。对于变异事件,浏览器每次你都必须遍历潜在的巨大 DOM 树变化。对于观察者,您可以通过选择不查看子树等来缩小您的兴趣范围。如果您有兴趣了解特定优势,请参阅此帖子
2021-05-08 20:31:22
@ŠimeVidas 对不起,是的,我的错误;我有供应商前缀,因为我在 Chrome 中测试。我现在已经标准化了供应商前缀,否则它应该可以正常工作。MutationObserver在 Firefox 和WebKitMutationObserverWebkit 中,但它们的工作方式相同。小提琴演示
2021-05-09 20:31:22
仅适用于 Chrome/Safari 的解决方案几乎不是合法的解决方案。
2021-05-18 20:31:22

使用 jQuery 时,可以简化MutationObserver用法,如下所示。

$("#btnAddDirectly").click(function () {
    $("#canvas").append($('<span class="stuff">new child direct</span>'));
});
$("#btnAddAsChildOfATree").click(function () {
    $("#canvas").append($('<div><div><span class="stuff">new child tree</span></div></div>'));
});

var obs = new MutationObserver(function(mutations, observer) {
  // using jQuery to optimize code
  $.each(mutations, function (i, mutation) {
    var addedNodes = $(mutation.addedNodes);
    var selector = "span.stuff"
    var filteredEls = addedNodes.find(selector).addBack(selector); // finds either added alone or as tree
    filteredEls.each(function () { // can use jQuery select to filter addedNodes
      alert('Insertion detected: ' + $(this).text());
    });
  });
});

var canvasElement = $("#canvas")[0];
obs.observe(canvasElement, {childList: true, subtree: true});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="canvas">
Canvas
</div>

<button id="btnAddDirectly">Add span directly to canvas</button>
<button id="btnAddAsChildOfATree">Add span as child of a tree</button>

不要忘了,第二个参数.observe()MutationObserverInit是很重要的:

在选项中,使用childList: trueifspan将仅作为直接子项添加。subTree: true如果它可以在任何级别以下#canvas

文档

  • childList: 设置为true是否要观察目标节点的子元素(包括文本节点)的添加和删除。
  • subtreetrue如果要观察到目标和目标的后代的突变设置为

突变观察者

// Select the node that will be observed for mutations
const targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
    // Use traditional 'for loops' for IE 11
    for(const mutation of mutationsList) {
        if (mutation.type === 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type === 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();

https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver