前端水印的实现方法总结

目录
文章目录隐藏
  1. 一、canvas 添加水印
  2. 二、通过 MutationObserver 监听水印
  3. 结语

前端水印实现方法,这里有两种方式,希望对大家有帮助。

一、canvas 添加水印

通过 canvas 生成 base64 图片,生成一个绝对定位的大小与 body 一样的 div–waterDiv,将 waterDiv 的背景设置为 canvas 的 base64 图片,将 waterDiv 挂在到 body 下面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div style='height: 100vh; width: 100%; background-color: red;'></div>
  <div style='height: 100vh; width: 100%; background-color: yellow;'></div>
  <div style='height: 100vh; width: 100%; background-color: blue;'></div>
  <div style='height: 100vh; width: 100%; background-color: black;'></div>
</body>
<script>
  function createWaterMark({
    container = document.body,
    width = 200,
    height = 200,
    fillStyle = 'rgba(220,220,220)',
    rotate = '30',
    zIndex = 100,
    font = '20px',
    content = '水印',
  }) {
     // 生成 canvas
    const canvas = document.createElement('canvas')
    // 设置宽高
    canvas.setAttribute('width', `${width}px`)
    canvas.setAttribute('height', `${height}px`)
    const ctx = canvas.getContext('2d')
    // 修改样式
    ctx.font = font
    ctx.fillStyle = fillStyle
    ctx.rotate((Math.PI / 180) * rotate)
    ctx.fillText(content, parseFloat(width) / 2, parseFloat(height / 2))
    // 转成 base64
    const base64url = canvas.toDataURL()
    // 生成水印 div 容器
    const waterDiv = document.createElement('div')
    // 添加样式
    waterDiv.setAttribute('style', `
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: ${zIndex};
      background-repeat: repeat;
      background-image: url('${base64url}');
	  pointer-events: none;
    `)
    container.style.position = 'relative'
    container.insertBefore(waterDiv, container.firstChild)
  }
  createWaterMark({
    content: '这是水印'
  })
</script>
</html>

效果如下:

前端开发实现水印的方法

二、通过 MutationObserver 监听水印

需要注意的是,通过这种方法虽然可以动态生成水印,但是通过浏览器控制台可以轻易将 waterDiv 删除,所以还需要监听认为删除水印节点时间以及修改水印样式事件,通过 MutationObderver 可以实现该功能。

MutationObserver 是在 DOM4 中定义的,用于替代 mutation events 的新 API,它的不同于 events 的是,所有监听操作以及相应处理都是在其他脚本执行完成之后异步执行的,并且是所以变动触发之后,将变得记录在数组中,统一进行回调的,也就是说,当你使用 observer 监听多个 DOM 变化时,并且这若干个 DOM 发生了变化,那么 observer 会将变化记录到变化数组中,等待一起都结束了,然后一次性的从变化数组中执行其对应的回调函数。

MutationObserver 的浏览器兼容范围。

方法

构造函数

用来实例化一个 Mutation 观察者对象,其中的参数是一个回调函数,它是会在指定的 DOM 节点发送变化后,执行的函数,并且会被传入两个参数,一个是变化记录数组(MutationRecord),另一个是观察者对象本身。

new MutationObserver(function(records, itself){});

observe

void observe(Node target, optional MutationObserverInit options)

其中的可选参数 MutationObserverInit 的属性如下:(需要使用的属性添加 true 即可)

  • childLIst:观察目标节点的子节点的新增和删除。
  • attributes:观察目标节点的属性节点(新增或删除了某个属性,以及某个属性的属性值发生了变化)。
  • characterData:如果目标节点为 characterData 节点(一种抽象接口,具体可以为文本节点,注释节点,以及处理指令节点)时,也要观察该节点的文本内容是否发生变化。
  • subtree:观察目标节点的所有后代节点(观察目标节点所包含的整棵 DOM 树上的上述三种节点变化)
  • attributeOldValue:在attributes属性已经设为 true 的前提下,将发生变化的属性节点之前的属性值记录下来(记录到下面 MutationRecord 对象的 oldValue 属性中)。
  • characterDataOldValue:在 characterData 属性已经设为 true 的前提下,将发生变化 characterData 节点之前的文本内容记录下来(记录到下面MutationRecord对象的oldValue属性中)
  • attributeFilter:一个属性名数组(不需要指定命名空间),只有该数组中包含的属性名发生变化时才会被观察到,其他名称的属性发生变化后会被忽略想要设置那些删选参数的话

disconnect

暂定在观察者对象上设置的节点的变化监听,直到重新调用observe方法。

使用 Mutation Observer 监听水印

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div style='height: 100vh; width: 100%; background-color: red;'></div>
  <div style='height: 100vh; width: 100%; background-color: yellow;'></div>
  <div style='height: 100vh; width: 100%; background-color: blue;'></div>
  <div style='height: 100vh; width: 100%; background-color: black;'></div>
</body>
<script>
  function createWaterMark({
    container = document.body,
    width = 200,
    height = 200,
    fillStyle  = 'rgba(220,220,220)',
    rotate = '30',
    zIndex = 1000,
    font = '20px microsoft yahei',
    content = '水印',
  }) {
    // 生成 canvas
    const canvas = document.createElement('canvas')
    // 设置宽高
    canvas.setAttribute('width', `${width}px`)
    canvas.setAttribute('height', `${height}px`)
    const ctx = canvas.getContext('2d')
    // 修改样式
    ctx.font = font
    ctx.fillStyle  = fillStyle 
    ctx.rotate((Math.PI / 180) * rotate)
    ctx.fillText(content, parseFloat(width) / 2, parseFloat(height / 2))
    // 转成 base64
    const base64url = canvas.toDataURL()
    const waterDiv = document.getElementById('waterDiv') || document.createElement('div')
    waterDiv.setAttribute('id', 'waterDiv')
    const style = `
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: ${zIndex};
      background-repeat: repeat;
      background-image: url('${base64url}');
      pointer-events: none;
    `
    // 添加样式
    waterDiv.setAttribute('style', style)
    // 修改父亲节点为相对定位
    container.style.position = 'relative'
    container.insertBefore(waterDiv, container.firstChild)
    const MutationObserver = window.MutationObserver || window.WebKitMutationObserver
    if (MutationObserver) {
      let handle = new MutationObserver(function() {
        const waterDiv = document.getElementById('waterDiv')
        // 触发修改时间后添加判断,符合条件时间才重新生成水印
        if ((waterDiv && waterDiv.getAttribute('style') !== style) || !waterDiv) {
          // 断开连接
          handle.disconnect();
          // 将函数置为空
          handle = null;
          // 重新调用函数
          createWaterMark({
            container,
            width,
            height,
            fillStyle,
            rotate,
            zIndex,
            font,
            content,
          })
        }
      })
      // 监听 body
      handle.observe(container, {
      attributes: true,
      subtree: true,
      childList: true
    })
    }
  }
  createWaterMark({
    content: '码云笔记'
  })
</script>
</html>

结语

以上就是码云笔记分享的前端水印实现方法,希望对大家有帮助,感谢阅读。

「点点赞赏,手留余香」

1

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 前端水印的实现方法总结

发表回复