估计看一眼手册知道有这么个东西,然后就再也不用,因为很少写原生 DOM 操作
找了很多帖子,都没有提到这个函数有两个巨坑,我来展示一下
<!DOCTYPE html>
<head>
<script>
const callback = mttns => {
mttns.forEach( mttn => {
[...mttn.addedNodes].forEach( node => {
if( node.nodeType !== 1 )
return;
if( node.querySelector('div p') )
console.log('div p ' + Math.random() );
if( node.querySelector('div a') )
console.log('div a ' + Math.random() );
} );
} );
};
const opts = { childList:true , subtree:true };
new MutationObserver(callback).observe( document , opts );
</script>
</head>
<body>
<div>
<p></p>
<script></script>
<a></a>
</div>
</body>
</html>
不用真的运行,推测一下控制台里 div p 和 div a 会出现几次?没用过的话会回答各出现一次。答案是 div p 会出现两次,而 div a 一次都没有
从那些千篇一律的文章中是找不到原因的,他们照着手册写个 demo 就撤了
虽然 MutationObserver 打着替代 DOMNodeInserted,DOMContentLoaded 的旗号,其实工作过程并不一致。对于普通的节点插入,MutationObserver 捕获的节点和 DOMNodeInserted 一样,但是对于整个 html 文档的第一次载入,也就是对应 DOMContentLoaded,MutationObserver 展示出了诡异之处
1 . 例子中的 html 片段,在首次载入时,并不是直接捕获一个 html 节点,而是
捕获 body > div > p
捕获 div > p
捕获 p
你问我是怎么回事?答案是回音,案是回音,是回音,回音,音
MutationObserver 会乐此不彼的重复这个过程,所以 node.querySelector('div p') 出现两次。这个行为和普通的节点插入完全不同
2 . 和 DOMContentLoaded 给你一个 document(注意不是 document.documentElement) 不同,MutationObserver 似乎把整个文档当作流,逐格吐出结果,并且这个流会被打断,也就是 script 标签
实际是这样的过程
注意没有 body > div > a,只有
body > div > p
div > p
p
script:你好打断一下
a <- 没有爹的孩子
所以 node.querySelector('div a') 一次都没有
为了移植一个脚本和这个东西纠缠一天,希望设计这个函数的祭天一下
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.