实现一个简单水印

晴天

今天用canvas画一个简单的水印

挂载点

const watermarkHookElement = document.body;
// 获取挂载element的几何信息
const rect = watermarkHookElement.getClientRects()[0];

创建canvas

const canvas = document.createElement('canvas');
canvas.width = rect.width;
canvas.height = rect.height;
canvas.style.cssText = 'position: absolute;left: 0;top: 0;z-index: -1;';
watermarkHookElement.appendChild(canvas);

计算水印个数

// 这里的20、50 均可以当做配置项参数
const xCount = rect.width / 20;
const yCount = rect.height / 50;

渲染水印

const ctx = canvas.getContext('2d');
for (let i = 0; i < xCount; i++) {
    for (let j = 0; j < yCount; j++) {
        ctx.save();
        // 重新设置canvas图层的中心点
        ctx.translate(i * 140 + 10, j * 70 + 60);
        // 单个水印逆时针旋转25度
        ctx.rotate(-25 * Math.PI / 180);
        ctx.fillStyle = '#ededee';
        ctx.font = '16px microsoft yahei';
        ctx.fillText('hello world', 0, 0);
        ctx.restore();
    }
}

关于canvas,可以去看 canvas学习笔记

效果图

image.png

resize

每次改变浏览器窗口大小的时候,上面的水印便会拉长或者压缩,加个动态的变化

window.addEventListener('resize', this.drawMark);

防删除

非小白用户总有自己想要干掉水印的冲动,控制台移除canvas节点,水印就木有了,所以对水印加个节点dom的监听,本文用的是MutationObserver

const observer = new MutationObserver(function(records) {          
    // 这里还可以做些优化, 去判断records的变化类型
    this.drawMark();
});
observer.observe(document.body, {
    attributes: true,
    childList: true,
    subtree: true
});

完整代码

写的时候是基于react写的,换其他框架或者原生都是可以的

import React from 'react';

interface IWaterMarkProps {}
interface IWaterMarkState {}
export default class WaterMark extends React.Component<IWaterMarkProps , IWaterMarkState> {

    canvas: Element|null;
    observer: any;
    constructor(props: IWaterMarkProps) {
        super(props);
        this.canvas = null;
        this.drawMark = this.drawMark.bind(this);
    }

    componentDidMount() {
        this.drawMark();
        window.addEventListener('resize', this.drawMark);
    }

    componentWillUnmount() {
        this.observer && this.observer.disconnect();
        this.canvas && this.canvas.remove();
        window.removeEventListener('resize', this.drawMark);
    }

    drawMark() {
        this.canvas && this.canvas.remove();
        const watermarkHookElement = document.body;
        const rect = watermarkHookElement.getClientRects()[0];
        const canvas = document.createElement('canvas');
        canvas.width = rect.width;
        canvas.height = rect.height;
        canvas.style.cssText= 'position: absolute;left: 0;top: 0;z-index: -1;';
        watermarkHookElement.appendChild(canvas);
        this.canvas = canvas;
        const xCount = rect.width / 20;
        const yCount = rect.height / 50;
        const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
        for (let i = 0; i < xCount; i++) {
            for (let j = 0; j < yCount; j++) {
                ctx.save();
                ctx.translate(i * 140 + 10, j * 70 + 60);
                ctx.rotate(-25 * Math.PI / 180);
                ctx.fillStyle = '#ededee';
                ctx.font = '16px microsoft yahei';
                ctx.fillText('hello world', 0, 0);
                ctx.restore();
            }
        }
        this.observer && this.observer.disconnect();
        this.observer = new MutationObserver((records) => {
            this.drawMark();
        });
        this.observer.observe(document.body, {
            attributes: true,
            childList: true,
            subtree: true
        });
    }

    render() {
        return (
            <div></div>
        );
    }
}

问题

  1. 在控制台中设置 html canvas { display: none; }, MutationObserver是无法监听到的,水印就被消除了。(虽然可以开定时器,反复添加水印,总感觉有些怪怪的)
  2. 当有弹窗时或者脱离文档流的内容时,水印被盖在下面了,无法看到,这种情况水印是怎么实现的呢 (监听每个body下所有dom的增添?为每个都增加水印吗?)

关于2 使用z-index: 99999; pointer-events: none; 来解决

看来想写一个通用且安全的水印还需要很多考虑,上面的问题有新的发现时会补充进来

去测试一下你们公司的水印的安全性如何吧~~

阅读 850
7 声望
3 粉丝
0 条评论
你知道吗?

7 声望
3 粉丝
文章目录
宣传栏