相关文章推荐
还单身的弓箭  ·  [实战] ...·  2 年前    · 
发呆的抽屉  ·  [Solved] This ...·  2 年前    · 

如何监听dom的变动?

当 DOM 发生变动,会触发 MutationObserver 事件 var observer = new MutationObserver(callback)

  • 文档: developer.mozilla.org/zh-CN/docs/…
  • MutationObserver 优点

    优化频繁操作dom的效率

  • 举例来说,如果在文档中连续插入 1000 个段落(p元素),就会连续触发 1000 个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;
  • 而 MutationObserver 不同,只在 1000 个段落都插入结束后才会触发,而且只触发一次。
  • 与事件的区别(概念上,接近事件)

  • 事件:是同步触发。
  • 当 DOM 发生变动,立刻会触发相应的事件;
  • MutationObserver :是异步触发
  • DOM 发生变动以后,并不会马上触发,而是要等到当前所有 DOM 操作都结束后才触发。
  • 代码举例:

    <!DOCTYPE html>
    <html lang="en">
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
      <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>
        <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>
    

    码字不易,点赞鼓励

    分类:
    前端
    标签: