Skip to content
文档章节

网页背景水印

原理是在canvas或svg创建背景图片,输出 base64 格式图片附在页面元素上面,调整图片颜色,同时通过 cs s样式 points-events:none隐藏点击效果。

canvas水印

预览链接 网页预览打开

预览效果如下, 可以看到已经有了背景水印

canvas水印

详细代码
html
<body>
    <div>页面内容</div>

    <script>
      function canvasWM({
        container = document.body,
        width = 200,
        height = 100,
        text = '请勿泄露',
        zIndex = 1000,
        rotate = -14,
        fillStyle = 'rgba(184, 184, 184, 0.4)',
      }) {
        // 创建画布
        const canvas = document.createElement('canvas');

        // 设置画布样式
        canvas.setAttribute('width', width);
        canvas.setAttribute('height', height);
        // canvas.setAttribute('display', 'none');

        const ctx = canvas.getContext('2d');
        // 设置内容样式
        ctx.font = '20px Microsoft YaHei';
        // 文本横向对齐方式
        ctx.textAlign = 'left';
        // 文本纵向对齐方式
        ctx.textBaseline = 'middle';

        ctx.fillStyle = fillStyle;

        ctx.rotate((Math.PI / 180) * rotate);
        // 设置文本内容
        ctx.fillText(text, canvas.width / 3, canvas.height / 2);

        // 获取页面水印元素,替换样式

        const base64URL = canvas.toDataURL();

        let wm = document.querySelector('.wm');
        const wmDiv = wm || document.createElement('div');

        const wmStyle = `
          position: fixed;
          top: 0;
          left: 0;
          right: 0;
          right: 0;
          width: 100%;
          height: 100%;
          z-index: ${zIndex},
          pointer-events:none;
          background-image: url('${base64URL}');
          background-repeat: repeat;
        `;

        wmDiv.setAttribute('style', wmStyle);
        wmDiv.classList.add('wm');

        if (!wm) {
          container.insertBefore(wmDiv, container.firstChild);
        }
      }

      canvasWM({});
    </script>
    <style>
      body {
        height: 100vh;
      }
    </style>
  </body>

优缺点

优点: 实现简单

缺点:使用了页面css和div元素,可以被屏蔽掉,也可以直接删除元素,从而删除水印。

svg水印

与canvas类似,不过是水印换成了svg图片了, 好处是兼容性更好

js
const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${width}">
  <text x="50%" y="50%" dy="12px"
    text-anchor="middle"
    stroke="#000000"
    stroke-width="1"
    stroke-opacity="${opacity}"
    fill="none"
    transform="rotate(-45, 120 120)"
    style="font-size: ${font};">
    ${content}
  </text>
</svg>`;
const base64Url = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgStr)))}`;

无论是canvas还是svg都是在页面插入元素,是可以被屏蔽或者删除掉的。如果元素被删除掉了,就不能防止别人截图了。

可以考虑设置定时器,定期刷新页面。网上有另外的方案,使用 MutationObserver 监听 dom 的变动,比如 wm样式改变或者被删除都会重新渲染, 这种方案更好。但是着这种方案中 container 元素发生变化可以监听, 但是当删除 container 后,监听也就停止了。

详细代码
html
<body>
  <div>页面内容</div>

  <script>
    function canvasWM({
      container = document.body,
      width = 200,
      height = 100,
      text = '请勿泄露',
      zIndex = 1000,
      rotate = -14,
      fillStyle = 'rgba(184, 184, 184, 0.4)',
    }) {
      console.log(`渲染水印`);
      const args = arguments[0];
      // 创建画布
      const canvas = document.createElement('canvas');

      // 设置画布样式
      canvas.setAttribute('width', width);
      canvas.setAttribute('height', height);
      // canvas.setAttribute('display', 'none');

      const ctx = canvas.getContext('2d');
      // 设置内容样式
      ctx.font = '20px Microsoft YaHei';
      // 文本横向对齐方式
      ctx.textAlign = 'left';
      // 文本纵向对齐方式
      ctx.textBaseline = 'middle';

      ctx.fillStyle = fillStyle;

      ctx.rotate((Math.PI / 180) * rotate);
      // 设置文本内容
      ctx.fillText(text, canvas.width / 3, canvas.height / 2);

      // 获取页面水印元素,替换样式

      const base64URL = canvas.toDataURL();

      let wm = document.querySelector('.wm');
      const wmDiv = wm || document.createElement('div');

      const wmStyle = `
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        right: 0;
        width: 100%;
        height: 100%;
        z-index: ${zIndex},
        pointer-events:none;
        background-image: url('${base64URL}');
        background-repeat: repeat;
      `;

      wmDiv.setAttribute('style', wmStyle);
      wmDiv.classList.add('wm');

      if (!wm) {
        container.insertBefore(wmDiv, container.firstChild);
      }

      const MutationObserver = window.MutationObserver;

      if (MutationObserver) {
        // 观察器的配置(需要观察什么变动)
        const config = { attributes: true, childList: true, subtree: true };

        // 当观察到变动时执行的回调函数
        const callback = function (mutationsList, observer) {
          // Use traditional 'for loops' for IE 11
          for (let mutation of mutationsList) {
            if (mutation.type === 'childList') {
              console.log('A child node has been added or removed.');
            } else if (mutation.type === 'attributes') {
              console.log('The ' + mutation.attributeName + ' attribute was modified.');
            }
          }

          // 之后,可停止观察, 避免重复调用
          observer.disconnect();

          canvasWM(JSON.parse(JSON.stringify(args)));
        };

        // 创建一个观察器实例并传入回调函数
        const observer = new MutationObserver(callback);

        // 以上述配置开始观察目标节点
        observer.observe(container, config);
      }
    }

    canvasWM({});
  </script>
  <style>
    body {
      height: 100vh;
    }
  </style>
</body