我有一个简单的MutationObserver设置作为测试。 HTML有一个span,其文本内容每秒更新一次(还有一个用于消息的div):

<span class="tester"></span>
<div id="msg"></div>

MutationObserver设置为监视.tester,并在观察到更改时将文本写入#msg div。同时,setInterval()运行一次/秒以更改.tester中的文本:
var target = document.querySelector('.tester');

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation.type);
    $('#msg').append(mutation.type+"<br/>")
    setTimeout(function() { $('#msg').text(''); }, 500);
  });
});

var config = { attributes: true, childList: true, characterData: true };
observer.observe(target, config);

setInterval(function() {
  $('#msg').text('');
  $('.tester').text("update: "+Math.random())
}, 1000);

我希望该代码每秒可以打印一次characterData已更改。根据Mozilla's docs for MutationObserver的说法,它关于characterData:“如果要观察到目标数据的变异,则设置为true。”相反,我没有看到characterData突变,但是每秒确实看到两个childList突变。

为什么我看不到任何characterData突变,为什么我看到两个childList突变?

这是CodePen的工作示例。

最佳答案

原因是Jeremy Banks said:使用jQuery的text()时,它将删除所有文本节点,然后添加新的文本节点。这不是对字符数据的更改,而是对childList的更改:删除那里的节点并用新节点替换它。
要查看字符数据的更改,您必须修改现有文本节点的nodeValue观察subtree的修改:

var target = document.querySelector('.tester');

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        console.log(mutation.type);
        $('#msg').append(mutation.type+"<br/>")
        setTimeout(function() { $('#msg').text(''); }, 500);
    });
});

var config = {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true                   // <=== Change, added subtree
};
observer.observe(target, config);

var timer = setInterval(function() {
    $('#msg').text('');
    // Change --VVVVV modifying the existing child node
    $('.tester')[0].firstChild.nodeValue = "updated" + Math.random();
}, 1000);

// Stop after 10 seconds
setTimeout(function() {
    clearInterval(timer);
}, 10000);
<span class="tester">x</span><!-- Change, added a starting child node -->
<div id="msg"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


再问一下关于为什么有两个childList突变的问题,是的,我认为您是对的:他们要删除 child ,然后添加一个 child 。如果我们使用 replaceChild method,我们只会看到一个突变:

var target = document.querySelector('.tester');

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        console.log(mutation.type);
        $('#msg').append(mutation.type+"<br/>")
        setTimeout(function() { $('#msg').text(''); }, 500);
    });
});

var config = {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true                   // <=== Change, added subtree
};
observer.observe(target, config);

var timer = setInterval(function() {
    $('#msg').text('');
    // Change --VVVVV modifying the existing child node
    var text = document.createTextNode("updated" + Math.random());
    var parent = $('.tester')[0];
    parent.replaceChild(text, parent.firstChild);
}, 1000);

// Stop after 10 seconds
setTimeout(function() {
    clearInterval(timer);
}, 10000);
<span class="tester">x</span><!-- Change, added a starting child node -->
<div id="msg"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

09-15 19:18