步骤如下
- 通过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,超出范围也会选择默认值
- 该方法是返回一个包含图片展示的数据URL。该url为base64形式,可以使用
-
mutationObserver:
提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品