深入探討前端水印


1、如何給頁面添加定制水印

定制水印一般指的是可以指定任何文字,給頁面添加定制水印有多種方法:

  • 背景圖方式
  • 創建元素,懸浮在頁面之上的方式

 

1.1、通過背景圖給頁面添加定制水印(會被子元素的背景覆蓋)

通過背景圖添加定制水印:

  • 首先制做定制水印,定制水印可以通過 canvas 繪畫出來
  • 然后通過 background-image 屬性將 canvas 制做的水印作為元素的背景圖添加進去
<div id="wrapDiv" style="background-color: antiquewhite">
    <h1>添加水印。。。。。</h1>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
</div>


<script>
    function addWaterMarker(divId, str) {
        //創建一個畫布
        var can = document.createElement('canvas');

        var waterMarkerDiv = document.getElementById(divId);
        waterMarkerDiv.appendChild(can);

        //設置畫布的樣式
        can.width = 400;
        can.height = 300;
        can.style.display = 'none';

        //創建context對象
        var ctx = can.getContext('2d');

        //將context旋轉-20度
        ctx.rotate(-20 * Math.PI / 180);

        //定義字體樣式
        ctx.font = "20px Microsoft JhengHei";

        //設置字體顏色
        ctx.fillStyle = "rgba(17, 17, 17, 0.50)";
        //文本橫向對齊方式
        ctx.textAlign = 'left';
        //文本縱向對齊方式
        ctx.textBaseline = 'Middle';

        //繪制實心文本,初始橫坐標為畫布寬度的1/3,初始縱坐標為畫布高度的一半
        ctx.fillText(str, can.width / 3, can.height / 2);

        //將畫布設為元素的背景,並且重復,達成水印的效果
        waterMarkerDiv.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")";
    }

    addWaterMarker('wrapDiv', '定制的水印123。。。')
</script>

效果:

 可以看到用背景圖添加水印有一個很大的缺點,那就是當添加了背景水印的元素的子元素有背景顏色或者是背景圖時,將會把該元素的水印給遮擋住,當子元素很多,並且都需要有背景時,這時候水印可能會導致被幾乎全部遮擋住,並且往往水印的要求是需要懸浮在頁面所有元素之上的。

 

1.2、創建元素,懸浮在頁面之上的方式(只適用於 IE11及以上版本)

動態創建元素的方式:

  • 動態創建元素,往元素里面添加需要定制的文本內容
  • 設置元素懸浮在頁面之上,通過absolute、z-index屬性
  • 設置創建的元素 pointer-events 為 none,則懸浮在頁面之上的元素將不會捕獲到任何事件,事件將會直接觸發懸浮元素之下的元素

這種方式的關鍵在於 pointer-events 屬性,將該屬性設置為 none,則該元素將不會是鼠標事件的目標,鼠標事件會“穿透”該元素。

//動態創建水印元素的封裝函數 shuiyin.js
function watermark(settings) {
    //默認設置
    var defaultSettings = {
        watermark_txt: "text",
        watermark_x: 20, //水印起始位置x軸坐標
        watermark_y: 20, //水印起始位置Y軸坐標
        watermark_rows: 20, //水印行數
        watermark_cols: 20, //水印列數
        watermark_x_space: 100, //水印x軸間隔
        watermark_y_space: 50, //水印y軸間隔
        watermark_color: '#aaa', //水印字體顏色
        watermark_alpha: 0.4, //水印透明度
        watermark_fontsize: '15px', //水印字體大小
        watermark_font: '微軟雅黑', //水印字體
        watermark_width: 210, //水印寬度
        watermark_height: 80, //水印長度
        watermark_angle: 20 //水印傾斜度數
    };
    //根據函數的入參調整設置
    if (arguments.length === 1 && typeof arguments[0] === "object") {
        var src = arguments[0] || {};
        for (key in src) {
            if (src[key] && defaultSettings[key] && src[key] === defaultSettings[key]) continue;
            else if (src[key]) defaultSettings[key] = src[key];
        }
    }

    //創建虛擬節點對象,在該節點對象中可以放元素,最后只需在頁面中添加該節點對象即可。可提高性能
    var oTemp = document.createDocumentFragment();

    //獲取頁面最大寬度
    var page_width = Math.max(document.body.scrollWidth, document.body.clientWidth);
    var cutWidth = page_width * 0.0150;
    var page_width = page_width - cutWidth;

    //獲取頁面最大高度
    var page_height = Math.max(document.body.scrollHeight, document.body.clientHeight) + 450;
    page_height = Math.max(page_height, window.innerHeight - 30);

    //如果將水印列數設置為0,或水印列數設置過大,超過頁面最大寬度,則重新計算水印列數和水印x軸間隔
    if (defaultSettings.watermark_cols == 0 || (parseInt(defaultSettings.watermark_x + defaultSettings.watermark_width * defaultSettings.watermark_cols + defaultSettings.watermark_x_space * (defaultSettings.watermark_cols - 1)) > page_width)) {
        defaultSettings.watermark_cols = parseInt((page_width - defaultSettings.watermark_x + defaultSettings.watermark_x_space) / (defaultSettings.watermark_width + defaultSettings.watermark_x_space));
        defaultSettings.watermark_x_space = parseInt((page_width - defaultSettings.watermark_x - defaultSettings.watermark_width * defaultSettings.watermark_cols) / (defaultSettings.watermark_cols - 1));
    }

    //如果將水印行數設置為0,或水印行數設置過大,超過頁面最大長度,則重新計算水印行數和水印y軸間隔
    if (defaultSettings.watermark_rows == 0 || (parseInt(defaultSettings.watermark_y + defaultSettings.watermark_height * defaultSettings.watermark_rows + defaultSettings.watermark_y_space * (defaultSettings.watermark_rows - 1)) > page_height)) {
        defaultSettings.watermark_rows = parseInt((defaultSettings.watermark_y_space + page_height - defaultSettings.watermark_y) / (defaultSettings.watermark_height + defaultSettings.watermark_y_space));
        defaultSettings.watermark_y_space = parseInt(((page_height - defaultSettings.watermark_y) - defaultSettings.watermark_height * defaultSettings.watermark_rows) / (defaultSettings.watermark_rows - 1));
    }

    var x;
    var y;

    console.log('水印行數', defaultSettings.watermark_rows);
    console.log('水印列數', defaultSettings.watermark_cols);

    for (var i = 0; i < defaultSettings.watermark_rows; i++) {
        y = defaultSettings.watermark_y + (defaultSettings.watermark_y_space + defaultSettings.watermark_height) * i;
        for (var j = 0; j < defaultSettings.watermark_cols; j++) {
            x = defaultSettings.watermark_x + (defaultSettings.watermark_width + defaultSettings.watermark_x_space) * j;
            var mask_div = document.createElement('div');
            mask_div.id = 'mask_div' + i + j;
            mask_div.className = 'mask_div';
            mask_div.appendChild(document.createTextNode(defaultSettings.watermark_txt));
            //設置水印div傾斜顯示
            mask_div.style.webkitTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.MozTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.msTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.OTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.transform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.visibility = "";
            mask_div.style.position = "absolute";
            mask_div.style.left = x + 'px';
            mask_div.style.top = y + 'px';
            mask_div.style.overflow = "hidden";
            mask_div.style.zIndex = "9999";
            //讓水印不遮擋頁面的點擊事件
            mask_div.style.pointerEvents = 'none';
            mask_div.style.opacity = defaultSettings.watermark_alpha;
            mask_div.style.fontSize = defaultSettings.watermark_fontsize;
            mask_div.style.fontFamily = defaultSettings.watermark_font;
            mask_div.style.color = defaultSettings.watermark_color;
            mask_div.style.textAlign = "center";
            mask_div.style.width = defaultSettings.watermark_width + 'px';
            mask_div.style.height = defaultSettings.watermark_height + 'px';
            mask_div.style.display = "block";
            oTemp.appendChild(mask_div);
        };
    };
    document.body.appendChild(oTemp);
}

function getNow() {
    var d = new Date();
    var year = d.getFullYear();
    var month = change(d.getMonth() + 1);
    var day = change(d.getDate());
    var hour = change(d.getHours());
    var minute = change(d.getMinutes());
    var second = change(d.getSeconds());

    function change(t) {
        if (t < 10) {
            return "0" + t;
        } else {
            return t;
        }
    }
    var time = year + '年' + month + '月' + day + '日 ' + hour + '時' + minute + '分' + second + '秒';
    return time;
}
<div>
    <h6>測試頁面 測試頁面</h6>
    <button onclick="showInfo()">點擊</button>
    <input type="text">
    <button onclick="showInfo()">點擊</button>
    <input type="text">
    <button onclick="showInfo()">點擊</button>
    <input type="text">
    <button onclick="showInfo()">點擊</button>
    <input type="text">
</div>

<script src="shuiyin.js"></script>
<script type="text/javascript">
    function showInfo() {
        console.log(111);
    }
    var now = getNow();
    watermark({
        "watermark_txt": "A B C X Y Z " + now
    });
</script>

效果:

可以看到,子元素的背景圖並不會把水印給擋住。

這種方式創建水印在 Chrome 及 IE11+ 版本的瀏覽器上是沒有問題的,但如果在IE11以下的版本,那就會出現問題:雖然展示的效果沒有差別,但是 pointer-events 屬性不再起作用,水印元素會捕獲到事件,並且水印元素能被選中,導致在水印之下的元素無法被事件捕獲到。

這是因為 pointer-events 屬性只能兼容到 IE11 版本的瀏覽器:

 

2、給頁面添加水印如何兼容IE11以下瀏覽器

給頁面添加水印兼容IE11以下瀏覽器,可以使用 SVG + 背景圖 的方式。在 SVG 元素上使用 pointer-events 屬性可以兼容低版本 IE,經測試可以兼容至 IE9,然后我們就可以給 SVG 元素添加水印作為背景圖,將 svg 元素懸浮在頁面之上,就可以實現添加水印的效果。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
<style>
    #wrapDiv {
        height: 500px;
        width: 100%;
        background-color: antiquewhite;
    }

    #svgDom {
        /* background-color: gold; */
        opacity: .5;
        height: 100%;
        width: 100%;
        position: absolute;
        top: 0;
        pointer-events: none;
    }
</style>
</head>

<body>
<div id="wrapDiv">
    <h1>添加水印。。。。。</h1>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
    <button onclick="btnClick()">點擊事件</button>
    <input type="text">
    <br>
</div>
<svg id="svgDom"></svg>

    <script>
        function btnClick() {
            console.log(123123);
        }

        function addWaterMarker(divId, str) {
            //創建一個畫布
            var can = document.createElement('canvas');

            var waterMarkerDiv = document.getElementById(divId);
            waterMarkerDiv.appendChild(can);

            //設置畫布的樣式
            can.width = 400;
            can.height = 200;
            can.style.display = 'none';

            //創建context對象
            var ctx = can.getContext('2d');

            //將context旋轉-20度
            ctx.rotate(-20 * Math.PI / 180);

            //定義字體樣式
            ctx.font = "20px Microsoft JhengHei";

            //設置字體顏色
            ctx.fillStyle = "rgba(17, 17, 17, 0.50)";
            //文本橫向對齊方式
            ctx.textAlign = 'left';
            //文本縱向對齊方式
            ctx.textBaseline = 'Middle';

            //繪制實心文本,初始橫坐標為畫布寬度的1/3,初始縱坐標為畫布高度的一半
            ctx.fillText(str, can.width / 3, can.height / 2);

            //將畫布設為元素的背景,並且重復,達成水印的效果
            waterMarkerDiv.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")";
        }

        addWaterMarker('svgDom', 'SVG定制水印123。。。')
    </script>
</body>

</html>

效果:

此時在低版本 IE 下水印不會捕獲到事件,水印也不會被選中,可以實現在低版本 IE(9)下實現水印的效果。

另外,也可以通過獲取在點擊的水印的位置下的元素,然后再主動觸發該元素的點擊事件來達到水印不捕獲事件的效果。(但是這種方式有點麻煩,因為你不知道水印下的元素被綁定的是點擊事件還是聚焦事件,或者是其他事件,這樣你就不知道應該觸發什么事件)

可參考:https://doc.weixiaoduo.com/knowledgebase/23002.html

 

3、暗水印

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM