指令实现水印功能

45 阅读2分钟

步骤如下

  • 通过canvas 实现水印文字,设置水印元素的背景base64url地址
  • 通过mutationObserver实现水印元素的监控

代码(ts版)如下:

let style = `
    display: block;
    overflow: hidden;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-repeat: repeat;
    pointer-events: none;`;

let globalCanvas: HTMLCanvasElement;
let globalWaterMark: HTMLElement;

type Directive = {
    mounted: (el: HTMLElement, binding: any) => void
}

// 取到水印背景url地址
const getDataUrl = ({
    font = "20px normal",
    fillStyle = "rgba(230,230, 90, 0.3)",
    textAlign = "center",
    fillText = "请勿外穿",
}) => {
    const canvas = globalCanvas || document.createElement('canvas');
    if (!globalCanvas) globalCanvas = canvas;
    const ctx = canvas.getContext('2d')
    if (!ctx) return
    ctx.font = font
    ctx.fillStyle = fillStyle
    ctx.fillText(fillText, 0, 20)
    return canvas.toDataURL('image/webp')     // 默认不传为‘image/png’
}

// 设置水印
const setWaterMark = (el: HTMLElement, binding: any) => {
    const url = getDataUrl({
        font: "20px normal",
        fillStyle: "rgba(230,230, 90, 0.3)",
        textAlign: "center",
        fillText: "请勿外穿",
    })

    const { parentElement, clientHeight, clientWidth } = el
    
    const parentElementStyle = `position:relative;width:${clientWidth}px; height: ${clientHeight}px`
    parentElement?.setAttribute('style', parentElementStyle)
    
    const waterMark = document.createElement('div')
    waterMark.className = 'water-mark'
    style = `background-image:url(${url})`
    waterMark.setAttribute('style', style)

    parentElement?.appendChild(waterMark)
}

// 监控
const observe = (el: HTMLElement, binding: any) => {
    const { parentElement } = el
    const observer = new MutationObserver((mutationList) => {
        if (!mutationList.length) return
        const { removedNodes, type, target } = mutationList[0]
        const waterMarkElement = document.querySelector('.water-mark')
        
        if (removedNodes[0] === waterMarkElement) {
            observer.disconnect()     //取消监控
            init(el, binding)
            return
        }
        
        const styleCurrent = waterMarkElement?.getAttribute('style')
        if (type === 'attributes' && target === waterMarkElement && styleCurrent !== style) {
            waterMarkElement.setAttribute('style', style)
        }
    })

    parentElement && observer.observe(parentElement, {
        childList: true,        //监控:添加,删除子元素
        attributes: true,       //监控:属性改变
        subtree: true           //监控:子元素的改变
    })
}

// 初始化
const init = (el: HTMLElement, binding: any) => {
    setWaterMark(el, binding)
    observe(el, binding)
}

const directive: Directive = {
    mounted(el: HTMLElement, binding: any) {
        el.onload = init.bind(null, el, binding)
    }
}
export default {
    name: "watermark",
    directive,
};

问题补充:

  • canvas.toDataURL : canvas.toDataURL(type, encoderOptions)

    • 该方法是返回一个包含图片展示的数据URL。该url为base64形式,可以使用 type 参数其类型,默认为 image/png 格式。图片的分辨率为96dpi。
    • encoderOptions:0到1之间的取值,主要用来选定图片的质量,默认值是0.92,超出范围也会选择默认值
  • mutationObserver: 提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品