给页面添加水印

378 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

给页面添加水印,你有什么招数

最近一位同学找到我,问:‘如何给页面添加水印,而且用户不能去除水印’,乍一看这题目,看似简单但要做完美还需要有一定前端知识储备的。为了保护知识产权,或者后台系统快速定位到个人,页面水印的存在是非常有必要的。接下来会尝试实现这个需求,本文从以下重点展开:

  • 如何生成水印
  • 将水印放到页面上
  • 如何禁止用户删除、篡改水印
  • 如何把水印做得更隐蔽

如何生成水印

如果水印是用来溯源,那么水印的内容可能会包含用户信息,因此水印的内容不是固定的。对于这种场景,一般可以由前端完成,通过 canvas 进行绘制,或者通过 svg 绘制也可以,这样可以减少与服务端的请求和资源开销。下面分别实现一下

// canvas 生成方式
    const canvas = document.createElement("canvas");
    canvas.width = document.body.clientWidth;
    canvas.height = document.body.clientHeight;
    const ctx = canvas.getContext("2d");
    const img = new Image();
    img.onload = () => {
        ctx.drawImage(img, 0, 0);
        canvas.toBlob((blob) => {
            const blobURL = URL.createObjectURL(blob);
            window.open(blobURL);
            URL.revokeObjectURL(blobURL);
        });
    };
    img.src = `data:image/svg+xml;charset=utf-8,${svg}`;


// svg 生成方式
<svg width="400" height="400" style="border: 1px solid red">
    <text style="fill: pink;fill-opacity:'0.2';transform: rotateX(45deg);">我是水印</text>
  </svg>

除了前端生成图片,也可以通过服务端返回图片的方式生成水印图片。

将水印放到页面上

在页面中插入一个全屏的,固定在页面的 div ,设置这个 div 的 background-image ,并设置 z-index 为最顶层,这样水印就出现在页面上了,但是这个 div 可能会遮挡其他元素,影响页面操作,因此还需要给这个元素增加 pointer-events: none; 属性,防止影响用户其他操作。

<div id="watermark"></div>

<style>
#watermark{
    z-index: 9999;
    pointer-events: none;
}
</style>

如何禁止用户删除、篡改水印

要防止一些人为修改,比如在浏览器控制台直接修改或删除对应的 DOM 元素,可以通过 MutationObserver 实现,监听用户行为,水印被修改或删除马上插入新的水印。

MutationObserver

MutationObserver 接口提供了监视对 DOM 树所做更改的能力。它被设计为旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。MutationObserver 创建并返回一个新的 MutationObserver 它会在指定的 DOM 发生变化时被调用。

// 选择需要观察变动的节点
const targetNode = document.getElementById("some-id");

// 观察器的配置(需要观察什么变动)
const config = { attributes: true, childList: true, subtree: true };

// 当观察到变动时执行的回调函数
const callback = function (mutationsList, observer) {
    const watermark = document.getElementById("watermark");
    
    watermark.innerHTML = `
        <svg width="400" height="400" style="border: 1px solid red">
            <text style="fill: pink;fill-opacity:'0.2';transform: rotateX(45deg);">我是水印</text>
        </svg>
    `;
    
};

// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback);

// 以上述配置开始观察目标节点
observer.observe(targetNode, config);

// 之后,可停止观察
observer.disconnect();

如何把水印做得更隐蔽

可以使用暗水印技术,将水印添加到图片或其他地方,可参考一下这篇文章: 链接