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

如何监听dom的变动?

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

MutationObserver 优点

优化频繁操作dom的效率

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

与事件的区别(概念上,接近事件)

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

代码举例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <div id="someElement">
  9. <div>111</div>
  10. <div>222</div>
  11. <div>3333</div>
  12. </div>
  13. <script>
  14. function handleClick (type) {
  15. const targetNode = document.querySelector("#someElement");
  16. if (type < 0) {
  17. targetNode.removeChild(targetNode.lastElementChild)
  18. } else {
  19. targetNode.appendChild(document.createElement('br'))
  20. }
  21. }
  22. </script>
  23. <div>
  24. <button onclick="handleClick(1)">+1</button>
  25. <button onclick="handleClick(-1)">-1</button>
  26. </div>
  27. <script>
  28. // MutationObserver 部分代码
  29. const targetNode = document.querySelector("#someElement");
  30. const callback = (obj) => {
  31. console.log(obj)
  32. }
  33. const observer = new MutationObserver(callback);
  34. observer.observe(targetNode, {
  35. childList: true, // 观察目标子节点的变化,是否有添加或者删除
  36. attributes: true, // 观察属性变动
  37. subtree: true // 观察后代节点,默认为 false
  38. })
  39. </script>
  40. </body>
  41. </html>

实际应用:防止水印被删除或更改

用 MutationObserver 防止水印被删除或更改

  1. // 此方法是防止用户通过 开发者工具 修改样式/或直接删除 祛除水印
  2. const observer = new MutationObserver(() => {
  3. const wmInstance = document.querySelector('.watermark') // 获取到你的水印dom
  4. if (!wmInstance) {
  5. console.log('水印被删除了!!!')
  6. document.body.appendChild(watermark)
  7. return
  8. }
  9. if (wmInstance.getAttribute('style') !== styleStr) {
  10. console.log('改水印样式了!!!')
  11. wmInstance.setAttribute('style', styleStr)
  12. }
  13. })
  14. observer.observe(document.body, {
  15. childList: true, // 观察目标子节点的变化,是否有添加或者删除
  16. attributes: true, // 观察属性变动
  17. subtree: true // 观察后代节点,默认为 false
  18. })

完整的代码:(生成canvas水印图片,用 MutationObserver 防止水印被删除或更改)

  1. <script>
  2. function watermark (text1, text2) {
  3. var canvas = document.createElement('canvas')
  4. canvas.width = 150
  5. canvas.height = 120
  6. canvas.style.display = 'none'
  7. var shuiyin = canvas.getContext('2d')
  8. // 控制文字的旋转角度和上下位置
  9. shuiyin.rotate(-20 * Math.PI / 180)
  10. shuiyin.translate(-50, 20)
  11. // 文字颜色
  12. shuiyin.fillStyle = '#dedede'
  13. // 文字样式
  14. shuiyin.font = '100 16px "PingFang SC", "Microsoft YaHei", Arial, sans-serif '
  15. shuiyin.fillText(text1, canvas.width / 3, canvas.height / 2)
  16. shuiyin.fillText(text2, canvas.width / 3, canvas.height / 2 + 20)
  17. /* 新建一个用于填充canvas水印的标签,之所以没有直接在body上添加,
  18. 是因为z-index对个别内容影响,才考虑的不用body */
  19. var watermark = document.createElement('div')
  20. const styleStr = `
  21. position:fixed;
  22. top:0;
  23. left:0;
  24. width:100vw;
  25. height:100vh;
  26. z-index:99;
  27. pointer-events:none;
  28. background-repeat:repeat;
  29. mix-blend-mode: multiply;
  30. background-image:url('${canvas.toDataURL('image/png')}')`
  31. watermark.setAttribute('style', styleStr)
  32. watermark.classList.add('watermark')
  33. document.body.appendChild(watermark)
  34. // 此方法是防止用户通过控制台修改样式去除水印效果
  35. /* MutationObserver 是一个可以监听DOM结构变化的接口。 */
  36. const observer = new MutationObserver((aa) => {
  37. // console.dir(aa)
  38. const wmInstance = document.querySelector('.watermark')
  39. if (!wmInstance) {
  40. console.log('水印被删除了!!!')
  41. document.body.appendChild(watermark)
  42. return
  43. }
  44. if (wmInstance.getAttribute('style') !== styleStr) {
  45. console.log('改水印样式了!!!')
  46. wmInstance.setAttribute('style', styleStr)
  47. }
  48. })
  49. observer.observe(document.body, {
  50. childList: true, // 观察目标子节点的变化,是否有添加或者删除
  51. attributes: true, // 观察属性变动
  52. subtree: true // 观察后代节点,默认为 false
  53. })
  54. }
  55. watermark('qwer', '你是qwer')
  56. </script>

码字不易,点赞鼓励