前端-如何监听dom的变动-防止水印被删除或更改
如何监听dom的变动?
当 DOM 发生变动,会触发 MutationObserver 事件
var observer = new MutationObserver(callback)
MutationObserver 优点
优化频繁操作dom的效率
- 举例来说,如果在文档中连续插入 1000 个段落(p元素),就会连续触发 1000 个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;
- 而 MutationObserver 不同,只在 1000 个段落都插入结束后才会触发,而且只触发一次。
与事件的区别(概念上,接近事件)
- 事件:是同步触发。
- 当 DOM 发生变动,立刻会触发相应的事件;
- MutationObserver :是异步触发
- DOM 发生变动以后,并不会马上触发,而是要等到当前所有 DOM 操作都结束后才触发。
代码举例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="someElement">
<div>111</div>
<div>222</div>
<div>3333</div>
</div>
<script>
function handleClick (type) {
const targetNode = document.querySelector("#someElement");
if (type < 0) {
targetNode.removeChild(targetNode.lastElementChild)
} else {
targetNode.appendChild(document.createElement('br'))
}
}
</script>
<div>
<button onclick="handleClick(1)">+1</button>
<button onclick="handleClick(-1)">-1</button>
</div>
<script>
// MutationObserver 部分代码
const targetNode = document.querySelector("#someElement");
const callback = (obj) => {
console.log(obj)
}
const observer = new MutationObserver(callback);
observer.observe(targetNode, {
childList: true, // 观察目标子节点的变化,是否有添加或者删除
attributes: true, // 观察属性变动
subtree: true // 观察后代节点,默认为 false
})
</script>
</body>
</html>
实际应用:防止水印被删除或更改
用 MutationObserver 防止水印被删除或更改
// 此方法是防止用户通过 开发者工具 修改样式/或直接删除 祛除水印
const observer = new MutationObserver(() => {
const wmInstance = document.querySelector('.watermark') // 获取到你的水印dom
if (!wmInstance) {
console.log('水印被删除了!!!')
document.body.appendChild(watermark)
return
}
if (wmInstance.getAttribute('style') !== styleStr) {
console.log('改水印样式了!!!')
wmInstance.setAttribute('style', styleStr)
}
})
observer.observe(document.body, {
childList: true, // 观察目标子节点的变化,是否有添加或者删除
attributes: true, // 观察属性变动
subtree: true // 观察后代节点,默认为 false
})
完整的代码:(生成canvas水印图片,用 MutationObserver 防止水印被删除或更改)
<script>
function watermark (text1, text2) {
var canvas = document.createElement('canvas')
canvas.width = 150
canvas.height = 120
canvas.style.display = 'none'
var shuiyin = canvas.getContext('2d')
// 控制文字的旋转角度和上下位置
shuiyin.rotate(-20 * Math.PI / 180)
shuiyin.translate(-50, 20)
// 文字颜色
shuiyin.fillStyle = '#dedede'
// 文字样式
shuiyin.font = '100 16px "PingFang SC", "Microsoft YaHei", Arial, sans-serif '
shuiyin.fillText(text1, canvas.width / 3, canvas.height / 2)
shuiyin.fillText(text2, canvas.width / 3, canvas.height / 2 + 20)
/* 新建一个用于填充canvas水印的标签,之所以没有直接在body上添加,
是因为z-index对个别内容影响,才考虑的不用body */
var watermark = document.createElement('div')
const styleStr = `
position:fixed;
top:0;
left:0;
width:100vw;
height:100vh;
z-index:99;
pointer-events:none;
background-repeat:repeat;
mix-blend-mode: multiply;
background-image:url('${canvas.toDataURL('image/png')}')`
watermark.setAttribute('style', styleStr)
watermark.classList.add('watermark')
document.body.appendChild(watermark)
// 此方法是防止用户通过控制台修改样式去除水印效果
/* MutationObserver 是一个可以监听DOM结构变化的接口。 */
const observer = new MutationObserver((aa) => {
// console.dir(aa)
const wmInstance = document.querySelector('.watermark')
if (!wmInstance) {
console.log('水印被删除了!!!')
document.body.appendChild(watermark)
return
}
if (wmInstance.getAttribute('style') !== styleStr) {
console.log('改水印样式了!!!')
wmInstance.setAttribute('style', styleStr)
}
})
observer.observe(document.body, {
childList: true, // 观察目标子节点的变化,是否有添加或者删除
attributes: true, // 观察属性变动
subtree: true // 观察后代节点,默认为 false
})
}
watermark('qwer', '你是qwer')
</script>
码字不易,点赞鼓励