在系统开发过程中,一些数据或页面比较敏感的地方,客户会要求实现水印效果,防止内部人员截图或拍照泄露信息。

自定义文字水印顾名思义就是利用js在完成页面渲染的同时,往页面的最底层动态生成多个带水印信息的div

效果图如下:
html页面自定义文字水印效果案例-LMLPHP

这个解决方案在使用过程中不仅可以自定义水印内容,还可以自定义样式,如倾斜角angle、透明度opacity、字体fontFamily、字体大小fontsize、左右上下间隔等等。

其html内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>水印输出</title>
</head>
<body>
<div>
    <h6>HELLO WORLD</h6>
    <!--  省略部分代码  -->
</div>
<!--  引入js(路径根据项目情况确定)  -->
<script type="text/javascript" src="watermark.js"></script>
<script>
    // 自定义样式
    const setting = {
        "text": "测试水印", // 水印内容
        "innerDate": true, // 在水印下方增加日期
        "width": 110 // 水印宽度
    };
    // 渲染
    watermark.build(setting);
</script>
</body>
</html>

自定义属性如下:

const setting = {
                text: "广州XX公司授权",     // 默认水印内容
                beginX: 50,              // 默认起始x坐标
                endX: 0,                 // 默认结束x坐标
                beginY: 50,              // 默认起始y坐标
                endY: 0,                 // 默认结束y坐标
                intervalX: 150,          // 默认横向间隔宽度
                intervalY: 100,          // 默认纵向间隔高度
                opacity: 0.3,            // 字体透明度
                angle: 20,               // 字体倾斜度
                fontsize: '15px',        // 字体大小
                fontFamily: '微软雅黑',   // 字体
                width: 100,              // 水印(每个)宽度
                height: 80,              // 水印(每个)高度
                innerDate: false,        // 是否附带日期
            };

完整js如下:

/**
 * 自定义文字水印
 */
const watermark = function () {
    return {
        build: function(arg) {
            // 获取页面宽度
            let maxWidth = Math.max(document.body.scrollWidth, window.screen.width) - 20;
            // 获取页面高度
            let maxHeight = Math.max(document.body.scrollHeight, document.body.clientHeight) + 100;
            if (maxHeight === 0){
                console.info("该页面无敏感内容~");
                return;
            }
            const setting = {
                text: "广州XX公司授权",    // 默认水印内容
                beginX: 50,              // 默认起始x坐标
                endX: 0,                 // 默认结束x坐标
                beginY: 50,              // 默认起始y坐标
                endY: 0,                 // 默认结束y坐标
                intervalX: 150,          // 默认横向间隔宽度
                intervalY: 100,          // 默认纵向间隔高度
                opacity: 0.3,            // 字体透明度
                angle: 20,               // 字体倾斜度
                fontsize: '15px',        // 字体大小
                fontFamily: '微软雅黑',   // 字体
                width: 100,              // 水印(每个)宽度
                height: 80,              // 水印(每个)高度
                innerDate: false,        // 是否附带日期
            };
            // 默认变量与自定义变量结合
            if (arguments.length ===1 && typeof arguments[0] === "object"){
                const src = arguments[0] || {};
                for (const key in src){
                    if (!src.hasOwnProperty(key) || !src[key]){
                        continue;
                    }
                    for (const def in setting){
                        if (key === def){
                            setting[def] = src[key];
                        }
                    }
                }
            }
            // 计算列个数
            const cols = parseInt((setting.intervalX + maxWidth - setting.beginX - setting.endX) / (setting.width + setting.intervalX) + "");
            // 计算行个数
            const rows = parseInt((setting.intervalY + maxHeight - setting.beginY - setting.endY) / (setting.height + setting.intervalY) + "");
            // 水印内容附加日期
            if (setting.innerDate){
                const date = new Date();
                setting.text = [setting.text, "<br>", date.getFullYear(), "年", date.getMonth() + 1, "月", date.getDate(), "日"].join("");
            }
            const fragment = document.createDocumentFragment();
            let x, y;
            for (let i=0; i<rows; i++){
                y = setting.beginY + (setting.intervalY + setting.height) * i;
                for (let j=0; j<cols; j++){
                    x = setting.beginX + (setting.width + setting.intervalX) * j;
                    const element = document.createElement('div');
                    element.id = 'watermark' + i + j;
                    // 设置倾斜角
                    element.style.MozTransform = "rotate(-" + setting.angle + "deg)";
                    element.style.msTransform = "rotate(-" + setting.angle + "deg)";
                    element.style.OTransform = "rotate(-" + setting.angle + "deg)";
                    element.style.transform = "rotate(-" + setting.angle + "deg)";
                    element.style.position = "absolute";
                    element.style.left = x + 'px';
                    element.style.top = y + 'px';
                    element.style.overflow = "hidden";
                    element.style.zIndex = "9999";
                    element.style.pointerEvents = 'none';
                    element.style.opacity = setting.opacity;
                    element.style.fontSize = setting.fontsize;
                    element.style.fontFamily = setting.fontFamily;
                    element.style.color = '#aaa';
                    element.style.textAlign = "center";
                    element.style.width = setting.width + 'px';
                    element.style.height = setting.height + 'px';
                    element.style.display = "block";
                    element.innerHTML = setting.text;
                    fragment.appendChild(element);
                }
            }
            document.body.appendChild(fragment);
        }
    }
}();


  • 其中获取页面宽度去的是屏幕的分辨率window.screen.width考虑的是,当用户通过F12打开开发者工具并显示在左右两边时,此时刷新页面,通过document.body.clientHeight获取到的宽度是不包括开发者工具页面的宽度的,这时候水印就没有全部页面占满,那么用户关闭开发者工具时,并不会刷新页面重新生成水印,所以就会出现一边有水印而一遍没有,如此水印便失去了震慑能力,所以应该去屏幕分辨率较好。
  • 列的个数及行的个数是根据自定义或者默认的水印起始结束坐标、水印间隔宽高度、水印宽高度与页面的宽高度进行动态计算,也就是说我们可以通过印起始结束坐标、水印间隔宽高度、水印宽高度来控制水印的密集程度。
  • 此外,通过灵活设置起始坐标以及结束坐标可以设置仅仅在页面中的一小块区域出现水印,其他区域则不出现水印。
  • 函数的入参是一个json对象
04-17 03:35