web明水印

信息的不对称,对任何人都一样,就像白天不懂夜的黑。

背景:出于相对安全考虑,要求对网页加上明水印,考虑到水印要浮于内容之上,且不影响用户操作,本文对采用水印DOM节点的方法做一个描述。

一、功能点

  • 文本自定义
  • 颜色自定义
  • 旋转角度自定义
  • 水印覆盖整个随容器
  • 水印间距可调
  • 窗口大小变化水印重绘
  • 打印预览去水印
  • [×]防打开控制台篡改

二、实现思路
传入一个DOM容器或以body为默认容器,然后根据容器大小,计算出需要向容器中添加一定数量的绝对定位的水印节点,通过定位的方式分配各水印节点在容器中的位置

三、代码

export default class Wartermark {

    static defaultSettings = {
        fontSize:14,//单位px
        rotate:45//旋转角度
    };

    /**
    * text:文本
    * el:添加水印的容器,默认为body,支持选择器和DOM元素作为传参
    **/
    constructor(text,el){
        this.el = el;
        this.text = text;
        this.timerId = null;
    }

    init(){
        let el,
        textNode = document.createElement("div"),//母水印节点,其余节点皆由此节点克隆得到
        vGap = 10,//垂直间隔
        hGap = 10,//水平间隔
        cols = 0,//列
        rows = 0,//行
        textNodes = [],//水印节点
        textWidth = 0,//文字宽度:字体大小*字符数
        areaWidth = 0,//字体旋转后所占矩形区域宽度
        areaHeight = 0,//字体旋转后所占矩形区域高度
        clientHeight = 0,//容器高度
        clientWidth = 0;//容器宽度
        textNode.textContent = `${this.text}`;
        textNode.style = `//水印节点样式
            position:absolute;//可以改成fixed,则水印固定在整个屏幕,不随内容移动
            left:0;
            top:0;
            color:#ccc;
            opacity:0.5;
            white-space: nowrap;
            z-index:10000;
            transform:rotate(45deg);
            user-select:none;//避免水印文本被选中
        `;
        textNode.classList.add('water-mark');
        textWidth = Wartermark.defaultSettings.fontSize * this.text.length;
        areaWidth = Math.cos(Wartermark.defaultSettings.rotate * Math.PI/180) * textWidth;
        areaHeight = Math.sin(Wartermark.defaultSettings.rotate * Math.PI/180) * textWidth;
        textNodes.push(textNode);

        if(this.el) {
            if(typeof this.el === 'string'){
                el = document.querySelector(this.el);
            }else{
                el = this.el;
            }
        }

        el  = el || document.body;
        el.style.position = 'relative';//容器设置为相对定位
        clientWidth = el.scrollWidth;
        clientHeight = el.scrollHeight;

        cols = Math.ceil(clientWidth / (areaWidth + hGap)) + 1;
        rows = Math.ceil(clientHeight / (areaHeight + vGap)) + 1;
        
        while(rows > 0){//生成水印节点
            let prevNode = textNodes[textNodes.length - 1];
            let node = prevNode.cloneNode(true);
            if(textNodes.length % cols === 0){
                node.style.left = 0;
                node.style.top = parseFloat(prevNode.style.top) + areaHeight + 'px';
                rows--;
            }else{
                node.style.left = parseFloat(prevNode.style.left) + areaWidth + 'px';
            }
            
            textNodes.push(node);
        }

        
        
        textNodes.forEach(ele=>{
            el.appendChild(ele);
        });

        window.removeEventListener('resize',this.resizeHandle);
        window.addEventListener('resize',this.resizeHandle.bind(this));
        this.appendPrintstyle();
    }


    update(){//当容器大小变化时,需要调用此方法
        let marks = document.getElementsByClassName("water-mark");
        Array.prototype.slice.call(marks).forEach(ele=>{
            ele.parentNode.removeChild(ele);
        });
        this.init();
    }

    resizeHandle(){
        if(this.timerId){
            clearTimeout(this.timerId)
        }

        this.timerId = setTimeout(()=>{
            this.update();
            this.timerId = null;
        },500)
    }

    appendPrintstyle(){
        if(document.getElementById('cssWaterMark')){
            return;
        }
        let styleEl =  document.createElement('style');
        styleEl.setAttribute('type','text/css');
        styleEl.setAttribute('id','cssWaterMark');
        styleEl.innerText ='@media  print{ .water-mark{ display:none } }';
        document.head.appendChild(styleEl)
    }

    run(){
        if(document.getElementsByClassName("water-mark").length){
            this.update();
            return;
        }
        this.init();
    }
}


//使用
let instance = new Wartermark('这是水印');
instance.run();

最后,通过实践,还是直接用gwm这个轮子更划算。

备注:另有其他的实现方法是通过canvas或svg生成容器的水印背景(此方法生成的水印需要浮于内容之上时,需要考虑事件穿透pointer-events:none)。更深入的还有盲水印、隐写术等。

你可能感兴趣的:(css3,js编程,笔记)