网页添加水印

212 阅读1分钟

添加水印主要涉及到,首先画出水印图片, 然后生成一个div标签, div的背景为生成的水印图片,之后防止水印标签被改所以需要监测元素,元素变动后删除元素重新添加 。需要注意的是重新添加元素的时候要停止观察器,以及ie删除dom节点有异步会有一点延迟。

class Watermark {
  constructor (name, id) {
    this.name = name
    this.id = id
    this.watermarkWithPointerEvents()
  }

  /**
   * 创建标签元素
   */
  watermarkWithPointerEvents () {
    const src = this.getWatermarkCanvas()
    const waterEle = document.createElement('div')
    waterEle.style.width = '100%'
    waterEle.style.height = '100%'
    waterEle.style.pointerEvents = 'none'
    waterEle.style.overflow = 'hidden'
    waterEle.style.position = 'fixed'
    waterEle.style.top = 0
    waterEle.style.zIndex = 999
    waterEle.style.backgroundImage = `url(${src})`
    waterEle.id = 'watermark'
    document.body.appendChild(waterEle)

    this.watermarkObserver(waterEle)
  }

  /**
   * 绘制水印
   */
  getWatermarkCanvas () {
    var can = document.createElement('canvas')
    var watermarkText = `${this.name}/${this.id}`
    can.width = 240
    can.height = 300
    var ctx = can.getContext('2d')
    ctx.font = '32px sans-serif'
    ctx.translate(100, 210)
    ctx.rotate(-45 * Math.PI / 180)
    ctx.fillStyle = 'rgba(0, 0, 0, 0.06)'
    ctx.fillText(watermarkText, -40, -30)
    return can.toDataURL('image/png')
  }

  /**
   * 监听水印元素
   */
  watermarkObserver (targetNode) {
    // 检测兼容性 ie支持 11+
    const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
    if (!MutationObserver) return

    const _this = this
    // 创建一个观察器实例观察属性变动
    const observerTargetAttr = new MutationObserver(function (mutationsList, observer) {
      for (let mutation of mutationsList) {
        if (mutation.attributeName === 'style' || mutation.attributeName === 'id') {
          _this.watermarkModify(targetNode, observer, observerBody)
          break
        }
      }
    })

    // 创建一个观察器观察节点变动是否删除
    const observerBody = new MutationObserver(function (mutationsList, observer) {
      for (let mutation of mutationsList) {
        [...mutation.removedNodes].some(ele => {
          const flag = ele.id === 'watermark'
          if (flag) _this.watermarkModify(targetNode, observer, observerTargetAttr)
          return flag
        })
      }
    })

    // 观察属性
    observerTargetAttr.observe(targetNode, {
      attributes: true,   // 观察属性变动
      childList: false,  // 观察目标子节点的变化,是否有添加或者删除
      subtree: false,    // 观察后代节点
      attributeFilter: ['style', 'id']  // 筛选需要观察的属性
    })

    // 观察子元素 (mutationObserver  不支持当前监测当前节点的删除)
    observerBody.observe(document.body, {
      attributes: false,
      childList: true,
      subtree: false
    })
  }

  /**
   * 水印改变之后删除元素,停止观察,重新添加水印
   */
  watermarkModify (targetNode, observer1, observer2) {
    // 目标元素改变之后停止观察
    observer1 && observer1.disconnect()
    observer2 && observer2.disconnect()

    // 变动之后删除元素
    const Ele = document.getElementById('watermark')
    const removeTargetEle = Ele || targetNode;
    (removeTargetEle.remove && removeTargetEle.remove()) || (removeTargetEle.removeNode && removeTargetEle.removeNode(true))

    // 重新添加水印(ie上删除dom节点会有延迟,添加异步)
    setTimeout(() => {
      this.watermarkWithPointerEvents()
    })
  }
}

export default Watermark

// 使用
new Watermark('张三', '123456')