怎么给项目添加水印?

135 阅读1分钟

canvas 实现

原理是动态生成一个相对于容器绝对定位、布满容器的 div,设置其背景为 canvas 生成的图片。canvas 可以设置文本内容,然后通过 toDataURL 方法转为图片。

canvas

// src/utils/waterMark.ts
const getDataUrl = ({font="16px normal", fillStyle="rgba(180, 180, 180, 0.3)", text="请勿外传"})=>{
  const rotate = -20;
  const canvas = document.createElement("canvas")
  const ctx = canvas.getContext("2d")
  if(ctx){
    ctx.rotate((rotate * Math.PI) / 180)
    ctx.font = font
    ctx.fillStyle = fillStyle
    ctx.textAlign = "left"
    ctx.fillText(text, 100, 100)
  }
  return canvas?.toDataURL("image/png")
}

为元素添加水印:

// src/utils/waterMark.ts
const waterMarkUrl = getDataUrl({})
const waterMarkStyle = `background-image: url(${waterMarkUrl});position: absolute;left: 0;top: 0;width: 100%;height:100%;pointer-events:none;background-repeat: repeat;`
const setWaterMark = (parentElement: Element = document.body) => {
  const waterMark = document.createElement('div')
  waterMark.setAttribute('id', 'js-watermarker')
  waterMark.setAttribute("style", waterMarkStyle)
  if(parentElement){
    // 父元素设置相对定位
    parentElement.setAttribute("style", "position: relative;");
    // 将带水印的 div 添加到容器中
    parentElement.appendChild(waterMark);
  }
}

MutationObserver 防止水印不被去除

MutationObserver 接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。

// src/utils/waterMark.ts
const mutationConfig = {
  attributes: true,
  childList: true,
  subtree: true,
}

const callbackBody = function(mutationsList: MutationRecord[], observer: MutationObserver){
  const targetDom = document.querySelector('#js-watermarker')
  // 监听是否还有 #js-watermarker 元素
  if(!targetDom){
    setWaterMark()
  }else{
    const curStyle = targetDom?.getAttribute('style')
    // 有元素,但是 style 内容不一致,需要重新设置 style
    if(curStyle!==waterMarkStyle){
      // 避免进入死循环
      observerBody.disconnect()
      targetDom.setAttribute("style", waterMarkStyle)
    }
  }
}

const observerBody = new MutationObserver(callbackBody)

export default (parentElement?: Element)=>{
  window.onload = ()=>{
    setWaterMark(parentElement)
    observerBody.observe(document.body, mutationConfig)
  }

  window.onbeforeunload = ()=>{
    observerBody.disconnect()
  }
}

本文正在参加「金石计划」