跳到主要内容

MutationObserve 实战

为了防止时效性问题,所以这里我们自己制造一个页面来完成接下来的实战。

页面内容如下

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MutationObserve实战</title>
</head>
<body>
<div class="list"></div>
</body>
<script>
const list = document.querySelector(".list");
function createItem(name) {
const item = document.createElement("div");
item.innerText = name;
return item;
}
const render = () => {
list.innerHTML = "";
list.append(createItem("苹果"));
list.append(createItem("梨子"));
list.append(createItem("香蕉"));
};
render();
setInterval(() => {
render();
}, 1000);
</script>
</html>

代码还是比较简单的,每隔 1 秒钟清空 list 下的内容,然后重新绘制,我们的目标就是在 list 下创建一个按钮框,并且每次刷新后再重新渲染。

我们先写一个最简单的版本

let btn = document.createElement("button");
btn.innerText = "按钮";
btn.onclick = function () {
alert("我被点击了");
};
const list = document.querySelector(".list");
list.append(btn);

发现一秒钟以后按钮消失了,所以我们应该使用 MutationObserve 监听这个元素,看他的子元素变动情况

let btn = document.createElement("button");
btn.innerText = "按钮";
btn.onclick = function () {
alert("我被点击了");
};
const list = document.querySelector(".list");
const insertListBtn = () => {
list.append(btn);
};
let observer = new MutationObserver(function (mutations) {
console.log("mutations", mutations);
});
observer.observe(list, {
childList: true,
});
insertListBtn(btn);

这个时候发现每秒输出四个 Record

mutations (4) [MutationRecord, MutationRecord, MutationRecord, MutationRecord]

我们先看第一个,发现是删除 3 个 div 和一个 button,说明是list.innerHTML = "";生效了

addedNodes: NodeList []
attributeName: null
attributeNamespace:null
nextSibling:null
oldValue:null
previousSibling:null
removedNodes:NodeList(4) [div, div, div, button]
target:div.list
type:"childList"

剩下三个 Record 分别是三次list.append(createItem("xx"));所触发的,我们这里只简单展示一个即可

addedNodes:NodeList [div]
attributeName:null
attributeNamespace:null
nextSibling:null
oldValue:null
previousSibling:null
removedNodes:NodeList []
target:div.list
type:"childList"

所以我们思路非常简单,只需要获取到 Record 数组后循环遍历每个 Record 的 removedNodes 属性,如果在 removedNodes 属性中的数组中找到了 button 元素,就再次执行插入操作。

理论建立完毕,实战开始

let btn = document.createElement("button");
btn.innerText = "按钮";
btn.onclick = function () {
alert("我被点击了");
};
const list = document.querySelector(".list");
const insertListBtn = () => {
list.append(btn);
};
let observer = new MutationObserver(function (mutations) {
for (let index = 0; index < mutations.length; index++) {
const record = mutations[index];
//这里将Nodelist利用 Array.from函数转化为一个普通的Array,然后调用find函数,判断removedNodes数组里是否包含button
if (
Array.from(record.removedNodes).find((removeItem) => btn === removeItem)
) {
//如果发现button被删除了就再次执行插入
insertListBtn(btn);
}
}
});
observer.observe(list, {
childList: true,
});
insertListBtn(btn);

经过测试发现button已经可以监听到被销毁就再次自动创建了。