1.首先创建watermark.js(我的项目中是放在utils文件夹中,如果是其他文件下,记得更改引入路径),代码如下:

/**
 * 全局水印工具类(支持用户信息动态更新)
 */
import {parseTime} from '@/utils/common.js';
export default class Watermark {
  constructor(options = {}) {
    // 默认配置
    this.defaults = {
      fontSize: 12,
      color: 'rgba(150, 150, 150, 0.15)',
      rotate: -15, // 旋转角度
      rowSpace: 100, // 行间距
      colSpace: 160, // 列间距
      zIndex: 9998, // 水印层级
      userInfo: {} // 用户信息({ name: '', id: '' })
    };
    this.options = { ...this.defaults, ...options };
    this.watermarkId = 'uni-global-watermark'; // 水印元素ID
    this.observer = null; // 防篡改观察者
  }

  // 初始化水印
  init() {
    // 先移除已存在的水印(避免重复创建)
    this.remove();

    // 创建水印元素
    const watermarkEl = document.createElement('div');
    watermarkEl.id = this.watermarkId;
    watermarkEl.style.cssText = `
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      pointer-events: none;
      z-index: ${this.options.zIndex};
      background-repeat: repeat;
    `;

    // 生成水印背景图
    this.updateWatermarkUrl(watermarkEl);

    // 添加到页面
    document.body.appendChild(watermarkEl);

    // 启动防篡改监听
    this.watchTamper(watermarkEl);
  }

  // 更新水印图片(支持动态修改用户信息)
  update(options) {
    this.options = { ...this.options, ...options };
    const watermarkEl = document.getElementById(this.watermarkId);
    if (watermarkEl) {
      this.updateWatermarkUrl(watermarkEl);
    }
  }

  // 生成水印背景图URL
  updateWatermarkUrl(watermarkEl) {
    const { userInfo, fontSize, color, rotate, rowSpace, colSpace } = this.options;

    // 格式化用户信息为多行文本
    const textLines = [];
    if (userInfo.nickName) textLines.push(`${userInfo.nickName}|${parseTime(new Date())}`);
    
    const text = textLines.length > 0 ? textLines.join('\n') : '未登录用户';

    // 创建Canvas绘制水印
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = colSpace;
    canvas.height = rowSpace;

    // 设置字体样式
    ctx.font = `${fontSize}px sans-serif`;
    ctx.fillStyle = color;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';

    // 旋转画布
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate((rotate * Math.PI) / 180);
    ctx.translate(-canvas.width / 2, -canvas.height / 2);

    // 绘制多行文本
    text.split('\n').forEach((line, index) => {
      const y = canvas.height / 2 + (index - (text.split('\n').length - 1) / 2) * fontSize;
      ctx.fillText(line, canvas.width / 2, y);
    });

    // 设置为背景图
    watermarkEl.style.backgroundImage = `url(${canvas.toDataURL('image/png')})`;
  }

  // 监听水印是否被篡改(删除/隐藏)
  watchTamper(watermarkEl) {
    // 停止之前的监听
    if (this.observer) this.observer.disconnect();

    // 创建观察者
    this.observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        // 检查水印是否被移除
        if (!document.getElementById(this.watermarkId)) {
          this.init(); // 重新创建
        } else {
          // 检查水印是否被隐藏
          const style = getComputedStyle(watermarkEl);
          if (style.display === 'none' || style.opacity === '0' || style.zIndex < this.options.zIndex) {
            watermarkEl.style.display = 'block';
            watermarkEl.style.opacity = '1';
            watermarkEl.style.zIndex = this.options.zIndex;
          }
        }
      });
    });

    // 监听水印元素和父节点变化
    this.observer.observe(watermarkEl, { attributes: true, attributeFilter: ['style', 'id'] });
    this.observer.observe(document.body, { childList: true, subtree: true });
  }

  // 移除水印
  remove() {
    const watermarkEl = document.getElementById(this.watermarkId);
    if (watermarkEl) {
      document.body.removeChild(watermarkEl);
    }
    if (this.observer) {
      this.observer.disconnect();
    }
  }
}

2.在main.js中引入watermark.js

import Watermark from '@/utils/watermark';
// 初始化水印实例
const watermark = new Watermark({
  fontSize: 12,
  color: 'rgba(100, 100, 100, 0.12)',
  zIndex: 9998
});
// 从Vuex获取初始用户信息并创建水印
function initWatermarkWithUser() {
  const userInfo = JSON.parse(store.state.user.userInfo) || {};
  watermark.update({ userInfo });
}
// 首次初始化水印
if (process.env.VUE_APP_PLATFORM === 'h5') { // 仅H5端生效
  // 等待DOM加载完成
  document.addEventListener('DOMContentLoaded', () => {
    watermark.init();
    initWatermarkWithUser();
  });
}
// 监听用户信息变化(登录/退出时自动更新水印)
store.watch(
   // 根据自身项目获取存储的用户信息
  (state) => store.state.user.userInfo,
  (newUserInfo) => {
    watermark.update({ userInfo: JSON.parse(newUserInfo) });
  },
  { deep: true }
);

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐