前端-如何监听dom的变动-防止水印被删除或更改

6,245 阅读1分钟

前端-如何监听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 !important;
          top:0 !important;
          left:0 !important;
          width:100vw !important;
          height:100vh !important;
          z-index:99 !important;
          pointer-events:none !important;
          background-repeat:repeat !important;
          mix-blend-mode: multiply !important;
          background-image:url('${canvas.toDataURL('image/png')}') !important`
    watermark.setAttribute('style', styleStr)
    watermark.classList.add('watermark')
    document.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>

码字不易,点赞鼓励