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()
}
}
本文正在参加「金石计划」