介紹
MutationObserver
接口提供了監(jiān)視對DOM樹所做更改的能力凸主。
構(gòu)造函數(shù)
MutationObserver()
創(chuàng)建并返回一個新的MutationObserver
它會在指定的DOM發(fā)生變化時被調(diào)用既绕。
new MutationObserver(callback)
:當(dāng)每次DOM發(fā)生變化的時候都會觸發(fā)callback。
等所有的DOM操作完成之后一次執(zhí)行(異步)
方法
-
阻止 MutationObserver
實(shí)例繼續(xù)接收的通知芥被,直到再次調(diào)用其observe()
方法,該觀察者對象包含的回調(diào)函數(shù)都不會再被調(diào)用籽腕。 -
配置
MutationObserver
在DOM更改匹配給定選項(xiàng)時乾蓬,通過其回調(diào)函數(shù)開始接收通知。 -
從MutationObserver的通知隊(duì)列中刪除所有待處理的通知壁榕,并將它們返回到
MutationRecord
對象的新Array
中矛紫。
使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MutationObserver</title>
</head>
<body>
<div id="simple" class="test"> simple </div>
</body>
<script>
// mutations 變動數(shù)組 observer 觀察器實(shí)例
var observer = new MutationObserver(function (mutations, observer) {
mutations.forEach(function(mutation) {
// 執(zhí)行具體的操作
// 例如:頁面劫持
console.log(mutation)
})
})
// 開始監(jiān)聽頁面根元素 html 變化
observer.observe(document.getElementById("simple"), {
attributes: true, // 屬性變動
characterData: true, // 節(jié)點(diǎn)內(nèi)容或節(jié)點(diǎn)文本的變動
childList: true, // 子節(jié)點(diǎn)的變動
subtree: true, // 表示是否將觀察器應(yīng)用于該節(jié)點(diǎn)的所有后代節(jié)點(diǎn)
attributeOldValue: true, // 表示觀察 attributes 變動時,是否需要記錄變動前的屬性值
characterDataOldValue: true, // 表示觀察 characterData 變動時牌里,是否需要記錄變動前的值
attributeFilter: ["style"] // 數(shù)組颊咬,表示需要觀察的特定屬性 (比如: ["class", "src"])
});
// document.getElementById("simple").innerText = 123;
document.getElementById("simple").firstChild.nodeValue="test";
// document.getElementById("simple").setAttribute("style", "background-color:blue; color:red; border:1px solid black");
// document.getElementById("simple").style.height = "123px";
// document.getElementById("simple").innerHTML = "<p>rrr</p>";
// // 停止觀察, 調(diào)用該方法后牡辽,DOM 再發(fā)生變動喳篇,也不會觸發(fā)觀察器
// observer.disconnect();
// // 清除變動記錄,即不再處理未處理的變動态辛,改方法返回變動記錄的數(shù)組麸澜。
// observer.takeRecords();
// // 保存所有沒有被觀察器處理的變動
// var changes = observer.takeRecords();
// console.log(changes, "changes");
// // 停止觀察
// observer.disconnect();
// MutationRecord 對象
// type: 觀察的變動類型
// target:發(fā)生變動的DOM節(jié)點(diǎn)
// addedNodes:新增的DOM節(jié)點(diǎn)
// removeNodes:刪除的DOM節(jié)點(diǎn)
// previousSibling:前一個同級節(jié)點(diǎn),如果沒有則返回null
// nextSibling:下一個同級節(jié)點(diǎn)奏黑,如果沒有則返回null
// attributeName:發(fā)生變動的屬性炊邦。如果這只了 attributeFilter,則只返回預(yù)先指定的屬性
// oldValue:變動前的值熟史。這個屬性只對 attribute和characterData變動有效馁害,如果發(fā)生childList變動,則返回null
</script>
</html>
示例
-
水印不可刪
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="content"></div> </body> <script> function drawCanvas() { let content = document.getElementById("content"); let divContainer = document.body.appendChild(document.createElement('div')); content.appendChild(divContainer); let waterMarkercanvas = document.createElement('canvas'); let context = waterMarkercanvas.getContext('2d'); divContainer.appendChild(waterMarkercanvas); divContainer.id = 'divContainer' let backgroundUrl = null; divContainer.style.height = window.innerHeight + 'px'; divContainer.style.width = window.innerWidth + 'px'; waterMarkercanvas.width = "400"; waterMarkercanvas.height = "400"; context.font = "20px"; context.textAlign = "center"; context.fillStyle = "#0000ff"; context.fillText("我是水印", 100, 100); backgroundUrl = waterMarkercanvas.toDataURL('image/png'); divContainer.style.backgroundImage = `url(${backgroundUrl})`; } drawCanvas(); let callback = (mutations) => { mutations.forEach(mutation => { console.log(mutation,"mutation"); if(mutation.removedNodes.length > 0 && mutation.removedNodes[0].id == "divContainer" && mutation.addedNodes.length <= 0) { setTimeout(function() { console.log("新增") drawCanvas(); }, 3000) } }); }; let observer = new MutationObserver(callback); observer.observe(document.getElementById("content"), { childList: true, // subtree: true }); console.log(document.getElementsByTagName("div")) setTimeout(function() { console.log("刪除") document.getElementById("content").removeChild(document.getElementById("divContainer")); }, 3000) </script> </html>
防止運(yùn)營劫持:監(jiān)控
dom
蹂匹,不在白名單內(nèi)和安全標(biāo)簽內(nèi)的script
或者iframe
碘菜,都給予remove
刪除處理。