Vue<页面水印,防删除,防修改>

549 阅读1分钟

image.png 想了解更多使用 canvas 实现的水印效果,可参考 此篇文章 ~~

watermark.js

const watermark = {
  observer: null,
  watermarkDom: null,

  /**
   * 设置水印
   * @param {String|Array} texts - 水印文本,可以是字符串或字符串数组
   * @param {Object} options - 水印配置选项
   */
  set: function(texts, options = {}) {
    // 默认配置
    const defaultOptions = {
      spacing: 200, // 水印间距
      rotate: -30, // 旋转角度
      fontSize: 14, // 字体大小
      fontColor: '#ececec', // 字体颜色
      fontFamily: 'sans-serif', // 字体族
      fontWeight: '100', // 字体粗细
      zIndex: 99, // 层级
      textAlign: 'left'
    }

    // 合并配置
    const config = { ...defaultOptions, ...options }

    // 处理文本参数
    const textArray = Array.isArray(texts) ? texts : [texts]

    // 创建canvas并计算尺寸
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')

    // 计算文本最大宽度和总高度
    const maxWidth = Math.max(...textArray.map(text => ctx.measureText(text).width))
    const lineHeight = config.fontSize + 10
    const totalHeight = textArray.length * lineHeight

    // 设置canvas尺寸 (增加内边距)
    canvas.width = maxWidth + config.spacing
    canvas.height = totalHeight + config.spacing

    // 绘制透明背景
    ctx.fillStyle = 'red'
    ctx.fillRect(0, 0, canvas.width, canvas.height)

    // 设置文本样式
    ctx.fillStyle = config.fontColor
    ctx.font = `${config.fontWeight} ${config.fontSize}px ${config.fontFamily}`
    ctx.textAlign = config.textAlign
    ctx.textBaseline = 'middle'

    // 应用旋转 (如果需要)
    if (config.rotate !== 0) {
      const centerX = canvas.width / 2
      const centerY = canvas.height / 2
      ctx.translate(centerX, centerY)
      ctx.rotate(config.rotate * Math.PI / 180)
    }

    // 根据文本对齐方式计算x坐标
    let x
    switch (config.textAlign) {
      case 'left':
        x = config.rotate !== 0 ? -maxWidth / 2 : (canvas.width - maxWidth) / 2
        break
      case 'right':
        x = config.rotate !== 0 ? maxWidth / 2 : (canvas.width + maxWidth) / 2
        break
      case 'center':
      default:
        x = config.rotate !== 0 ? 0 : canvas.width / 2
        break
    }

    // 绘制文本
    const baseY = config.rotate !== 0 ? 0 : canvas.height / 2
    textArray.forEach((text, index) => {
      const y = baseY + (index - (textArray.length - 1) / 2) * lineHeight
      ctx.fillText(text, x, y)
    })

    // 移除旧水印
    if (this.watermarkDom) {
      document.body.removeChild(this.watermarkDom)
    }

    // 创建新水印
    this.watermarkDom = document.createElement('div')
    const styleStr = `
      position:fixed;
      top:0;
      left:0;
      width:100vw;
      height:100vh;
      z-index:${config.zIndex};
      pointer-events:none;
      mix-blend-mode:multiply;
      background-position:left top;
      background-image:url('${canvas.toDataURL('image/png')}');
      background-repeat:repeat;`

    this.watermarkDom.setAttribute('style', styleStr)
    this.watermarkDom.classList.add('watermark')
    document.body.appendChild(this.watermarkDom)
    this.initObserver(styleStr)
  },

  /**
   * 初始化观察器防止水印被删除
   */
  initObserver: function(styleStr) {
    // 先断开已有的观察器
    if (this.observer) {
      this.observer.disconnect()
    }

    // 创建新的观察器
    this.observer = new MutationObserver(() => {
      const wmInstance = document.querySelector('.watermark')
      if ((wmInstance && wmInstance.getAttribute('style') !== styleStr) || !wmInstance) {
        if (wmInstance) {
          wmInstance.setAttribute('style', styleStr)
        } else {
          this.observer.disconnect()
        }
      }
    })

    this.observer.observe(document.body, {
      attributes: true,
      subtree: true,
      childList: true
    })
  },

  /**
   * 移除水印
   */
  close: function() {
    const watermark = document.querySelector('.watermark')
    if (watermark) {
      document.body.removeChild(watermark)
    }

    // 断开观察器
    if (this.observer) {
      this.observer.disconnect()
      this.observer = null
    }

    this.watermarkDom = null
  }
}

export default watermark

使用方法:

    import watermark from '@/utils/watermark.js'

    //添加水印
     watermark.set(['1234567', '谁在花里胡哨'])

    //移除水印
     watermark.close()

2021-03-09 12-02-23.gif