页面增加水印及水印防删

从以下几点判断水印消失:

1.选用canvas 防止水印内容篡改

2.选用MutationObserver 监听水印的style属性是否被篡改和监听水印元素是否被删除

3.定时更新元素的z-index动态计算最大层级

watermark.js

javascript 复制代码
let obj = JSON.parse(window.localStorage.getItem("User"));
let watermarkUrl = createWatermark([obj.name, obj.account]);
function createWatermark (text = '默认水印') {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  // 设置canvas尺寸
  canvas.width = 200;
  canvas.height = 150;
  // 旋转文字
  ctx.rotate((-15 * Math.PI) / 180);
  // 设置文字样式
  ctx.font = '20px Microsoft YaHei';
  ctx.fillStyle = 'rgba(0, 0, 0,0.1)';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  // 绘制文字(支持多行)
  const texts = Array.isArray(text) ? text : [text];
  texts.forEach((line, i) => {
    ctx.fillText(line, canvas.width / 2, canvas.height / 2 + i * 20);
  });
  // 转为图片URL
  return canvas.toDataURL('image/png');
}

// 计算页面中最大的z-index
function getMaxZIndex () {
  // 获取所有可见元素
  const elements = document.querySelectorAll('body *:not(.watermark-layer)');
  let maxZ = 10; // 默认最低层级(确保至少高于普通内容)
  elements.forEach(el => {
    const position = window.getComputedStyle(el).position;
    // 只处理有定位的元素(z-index对static无效)
    if (position !== 'static') {
      const zIndex = window.getComputedStyle(el).zIndex;
      if (zIndex !== 'auto') {
        const z = parseInt(zIndex, 10);
        if (!isNaN(z) && z > maxZ) {
          maxZ = z;
        }
      }
    }
  });
  return maxZ;
}
let styleStr = `position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-image: url(${watermarkUrl});
      background-repeat: repeat;
      pointer-events: none; 
      z-index: ${getMaxZIndex() + 1};
      `
// 闭包封装水印防护逻辑
export function initWatermark () {
  console.log('创建元素');

  // 创建水印元素(初始层级为最大z-index +1)
  let watermarkEl = document.createElement('div');

  watermarkEl.className = 'watermark-layer';
  watermarkEl.style.cssText = styleStr

  document.body.appendChild(watermarkEl);
  const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      const watermarkEl = document.querySelector('.watermark-layer');
      if (!watermarkEl) {
        console.log('水印被删除,重新创建')
        observer.disconnect();
        initWatermark();

      }

      if (mutation.attributeName === 'style' && watermarkEl && watermarkEl.getAttribute('style') !== styleStr) {
        // 样式变化时,重新设置
        console.log('样式变化时,重新设置', styleStr)
        watermarkEl.setAttribute('style', styleStr);
      }

    });
  });
  observer.observe(document.body, {
    attributes: true,
    childList: true,
    subtree: true,
  });
  // 定时检查zIndex
  const checkTimer = setInterval(() => {
    zIndex();
  }, 300)
  // 清理函数 
  return () => {
    observer.disconnect();
    clearInterval(checkTimer);
  };

}

// 层级
function zIndex () {
  styleStr = `position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background-image: url(${watermarkUrl});
      background-repeat: repeat;
      pointer-events: none; 
      z-index: ${getMaxZIndex() + 1};
      
      `
  const watermarkEl = document.querySelector('.watermark-layer');
  watermarkEl.setAttribute('style', styleStr);
}

main.vue

javascript 复制代码
import { initWatermark } from '@/utils/watermark';  //引入
export default {
    data(){
        return{
             watermarkCleanup: null,
            }
    }
created(){
    //创建水印并保存清理函数
    const watermarkEl = document.querySelector('.watermark-layer');
    if (!watermarkEl) {
      // 保存清理函数的引用
      this.watermarkCleanup = initWatermark();

    }
}
  beforeDestroy () {
    // 调用清理函数来关闭定时器和页面元素监听
    if (this.watermarkCleanup) {
      this.watermarkCleanup();
    }
  }
}
复制代码
如有遗漏,欢迎指教补充