工作项目里实现过的需求,学习了相关代码总结出这篇文章

实现水印的思路

从页面层次上来看,水印可以理解为覆盖在最高层的一层透明背景,虽然覆盖在最高层,但是不应该影响底层任何事件的触发

可以通过 canvas 绘制字符串的图片,然后转化为图片作为背景循环平铺到一个 div 里

这个 div 就是水印图

代码实现

绘制水印图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function setWatermark(str: string): HTMLDivElement | null {
const id = "1.1351.1561.215515";
const lastEle = document.getElementById(id);

if (lastEle !== null) {
document.body.removeChild(lastEle);
}

const canvas = document.createElement("canvas");
const body = document.querySelector("body");

const clientWidth = body?.clientWidth ?? 0;
const clientHeight = body?.clientHeight ?? 0;

const ctx = canvas.getContext("2d");
if (!ctx) return null;

// 获取被测量字符串的宽度
const strWidth = ctx.measureText(str).width;
// 通过文字倾斜程度,算出canvas应有的宽高
const canvasW = strWidth * Math.cos((30 / 180) * Math.PI) + 100;
const canvasH = strWidth * Math.sin((30 / 180) * Math.PI) + 100;

canvas.style.width = `${canvasW}px`;
canvas.style.height = `${canvasH}px`;

canvas.width = canvasW;
canvas.height = canvasH;

// 绘制文字
ctx.rotate((-30 * Math.PI) / 180);
ctx.font = "14px PingFang SC";
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
ctx.textAlign = "left";
ctx.textBaseline = "bottom";
ctx.fillText(str, 0, canvas.height);

const ele = document.createElement("div");
ele.id = id;
ele.style.pointerEvents = "none";
ele.style.top = "0px";
ele.style.position = "fixed";
ele.style.zIndex = "100000";
// 覆盖body
ele.style.width = `${clientWidth}px`;
ele.style.height = `${clientHeight}px`;

// canvas 转 data:url
canvas.toBlob((blob) => {
const newImg = document.createElement("img");
const url = URL.createObjectURL(blob || new Blob());
newImg.onload = function () {
URL.revokeObjectURL(url);
};
ele.style.background = `url(${url}) left top repeat`;
});
document.body.appendChild(ele);
return ele;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Watermark {
// 设置水印
static set(str: string) {
let ele = setWatermark(str);

setInterval(() => {
if (
!ele ||
document.getElementById(ele.id) === null ||
!ele.style.background
) {
ele = setWatermark(str);
}
}, 500);

window.onresize = () => {
setWatermark(str);
};
}

static outWatermark(id: string) {
const div = document.getElementById(id);
if (div !== null && div) div.style.display = "none";
}
// 隐藏水印
static out() {
const id = "1.1351.1561.215515";
Watermark.outWatermark(id);
}
}

设置水印

1
Watermark.set(`吼姆小行星`);

隐藏水印:

1
Watermark.out();