如果要监听一个普通 JS 对象的变化,我们会用 Object.defineProperty 或者 Proxy
而监听元素的属性和子节点的变化,我们可以用 MutationObserver:
我第一听说这个方法还是在nextTick 的实现上看到的
由于要模拟在DOM 更新后执行回调函数,所以要将包裹内的同步任务转化为异步任务,又因为兼容性要好,其中一个兼容方案就是MutationObserver。
MutationObserver 可以监听对元素的属性的修改、对它的子节点的增删改。
测试
我们准备这样一个DIV
<div id="box"><button>我是DIV</button></div>
加上样式:
#box {
width: 100px;
height: 100px;
background: blue;
}
然后我们增加JS操作
setTimeout(() => {
box.style.background = 'red';
},2000);
setTimeout(() => {
const dom = document.createElement('button');
dom.textContent = '我是cheems';
box.appendChild(dom);
},3000);
setTimeout(() => {
document.querySelectorAll('button')[0].remove();
},4000);
2s 的时候修改背景颜色为红色
3s 的时候添加一个 button
4s 的时候删除第一个 button。
然后监听它的变化:
const mutationObserver = new MutationObserver((mutationsList) => {
console.log(mutationsList)
});
mutationObserver.observe(box, {
attributes: true,
childList: true
});
可以看到在三次变化的时候都监听到了并打印了信息
然后,这个可以用来做什么呢?
PS:我一开始也觉得没鸟用,因为MVVM都给我绑定好了,我监听值就好了,监听DOM干啥。
它可以监听用户是否主动操作了DOM,那些未绑定的属性如果被操作也可以被监听。这就引出了我下一期内容,防删除水印组件。如果没有就是还在鸽。
但是大家看看先内容监听Hooks与内容监听组件。
MutationObserver的接受细节请点击MDN,自行查看。
支持单个节点/多个节点的监听
有默认的 options
在DOM销毁的时候,主动调用 takeRecords 删掉所有剩余通知,调用 disconnect 停止接收新的通知
引入内容监听hooks
通过 React.cloneElement 给 children 加上 ref 来获取dom。
然后在 useLayoutEffect,调用setState存储ref,触发更新,
再次渲染的时候,调用 useMutateObserver 就有 dom 了,可以用 MutationObserver 来监听 dom 变化。
over,撤!