为什么MutationObserver为childList触发两次但从不为characterData触发?

mix*_*mix 6 javascript dom mutation-observers

我有一个简单的MutationObserver设置作为测试.HTML span的文本内容每秒更新一次(和div消息):

<span class="tester"></span>
<div id="msg"></div>
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

我希望这段代码每秒打印一次,因为characterData已经改变了.根据Mozilla的MutationObserver文档,它描述了characterData:"如果要观察目标数据的突变,则设置为true." 相反,我看不到characterData突变,但确实每秒看到两个childList突变.

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

这是CodePen的一个工作示例.

T.J*_*der 7

原因是Jeremy Banks说:当你使用jQuery时text(),它会删除所有文本节点,然后添加新的节点.这不是对字符数据的更改,而是对以下内容的更改childList:删除那里的节点并将其替换为新节点.

要查看字符数据的更改,您必须修改现有的文本节点nodeValue,观察subtree修改:

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

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    snippet.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);
Run Code Online (Sandbox Code Playgroud)
<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>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Run Code Online (Sandbox Code Playgroud)


你的问题是关于为什么有两个 childList突变,是的,我认为你是对的:他们正在移除孩子,然后添加一个新的.如果我们使用该replaceChild方法,我们只看到一个突变:

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

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    snippet.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);
Run Code Online (Sandbox Code Playgroud)
<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>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Run Code Online (Sandbox Code Playgroud)