点击查看代码
class WaterMark {
constructor(el, content) {
this.el = el;
this.content = content;
this.observer = null;
this.config = { attributes: true, childList: true, subtree: true };
this.init();
}
init() {
this.createContext(this.el);
}
createContext(elem) {
const { offsetWidth, offsetHeight } = elem;
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = offsetWidth;
canvas.height = offsetHeight;
canvas.style.position = "absolute";
canvas.style.pointerEvents = "none";
canvas.style.top = "0px";
canvas.style.left = "0px";
canvas.style.zIndex = "99";
ctx.font = "24px serif";
ctx.rotate((-20 * Math.PI) / 180);
ctx.fillStyle = "rgba(180, 180, 180, 0.6)";
ctx.textAlign = "left";
ctx.textBaseline = "middle";
for (let i = 0; i < canvas.width / 100; i++) {
for (let j = 0; j < canvas.height / 50; j++) {
ctx.fillText(this.content, i * 200, j * 100 + 20);
}
}
elem.appendChild(canvas);
this.createObserver(elem);
}
createObserver(elem) {
if (this.observer) this.observer.disconnect();
this.observer = new MutationObserver((changeList, watcher) => {
Array.from(changeList).forEach((record) => {
const { removedNodes } = record;
const removeNodeNames = Array.from(removedNodes).map(
(node) => node.nodeName
);
if (removeNodeNames.includes("CANVAS")) {
window.requestIdleCallback(() => this.createContext(elem), {
timeout: 300,
});
}
});
});
this.observer.observe(elem, this.config);
}
}
const elem = document.getElementById("content");
const waterMark = new WaterMark(elem, "hello, world");
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异