實現一個簡單水印

今天用canvas畫一個簡單的水印css

掛載點

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學習筆記html

效果圖

image.png

resize

每次改變瀏覽器窗口大小的時候,上面的水印便會拉長或者壓縮,加個動態的變化react

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

防刪除

非小白用戶總有本身想要幹掉水印的衝動,控制檯移除canvas節點,水印就木有了,因此對水印加個節點dom的監聽,本文用的是MutationObservercanvas

const observer = new MutationObserver(function(records) {          
    // 這裏還能夠作些優化, 去判斷records的變化類型
    this.drawMark();
});
observer.observe(document.body, {
    attributes: true,
    childList: true,
    subtree: true
});

完整代碼

寫的時候是基於react寫的,換其餘框架或者原生都是能夠的segmentfault

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的增添?爲每一個都增長水印嗎?)

看來想寫一個通用且安全的水印還須要不少考慮,上面的問題有新的發現時會補充進來瀏覽器

去測試一下大家公司的水印的安全性如何吧~~安全

相關文章
相關標籤/搜索