整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JavaScript奇技淫巧:防删水印

Shaman.com原创资料,作者:w3sft,如转载请保留此信息。

为了保护版权、防截图、防拍照等,有些我们会给网页中的视频、图片或文字加水印。

实现的方式,可能有多种,比如:对图片、视频而言,可以在服务端完成水印,但对于文字信息类,一般只能在前端页面中进行水印添加。

本文分享一种图层式防删水印技术。其效果是:在页面渲染完成后,由JavaScript进行图层水印添加,并会实时检测水印状态,如果水印被删除、隐藏、或设置为透明,都会重置水印。

源码

<html>
<body>
<div id="content" style="padding:10px;">
<h2>防删文字水印</h2>
水印内容不可删除,如检测到被删除,会重新添加水印
</div>
<script>
    function add_water_canvas(){
        //水印canvas
        var water_canvas = document.createElement("canvas");
        water_canvas.id = "water_canvas";
        water_canvas.height = 100;
        water_canvas.width = 300;
        water_canvas.style.top = 100 + "px";
        water_canvas.style.left = 100 + "px";
        water_canvas.style.position = "absolute";
        water_canvas.style.transform = "rotate(-45deg)";
        //水印内容
        var water_text = water_canvas.getContext("2d");
        water_text.font = "26px 黑体";
        water_text.fillText("水印内容", 30, 50);
        //canvas容器:水印目标
        var canvas_container = document.getElementById("content");
        canvas_container.style.height =  280 + "px";
        canvas_container.style.width = 500 + "px";
        canvas_container.style.backgroundImage = "url(bg.png)";
        //添加水印canvas给目标div
        canvas_container.appendChild(water_canvas);
    }
    add_water_canvas();
    var observer = new MutationObserver(function(mutations){
        mutations.forEach(function(mutation){
            if(mutation.removedNodes.length > 0 && mutation.removedNodes[0].id == "water_canvas") {
                console.log("检测到水印被删除,已重新添加水印");
                //重新添加水印
                add_water_canvas();
            }
            if (mutation.type == "attributes" && mutation.target.id == "water_canvas") {
                console.log("检测到水印属性被修改,已重置属性");
                water_canvas.style.display = "block";
                water_canvas.style.opacity = 1;
            }
        });
    });
    observer.observe(document.body, {
        childList: true,
        attributes: true,
        subtree: true,
        attributesOldValue: true,
        characterData: true,
        characterDataOldValue: true,
    });
</script>
</body>
</html>

技术原理

添加水印的方式平平无奇,只是新建了一个canvas图层,在图层中叠加水印内容。

取巧的是用MutationObserver对水印进行监控和重置。MutationObserver是一个很有创意的接口,它可以监听页面元素变化,任何元素的修改,如节点的增减、属性值更新、文本内容的改动都会触发MutationObserve事件,在本例中,会监测两种事件:节点删除、节点属性发生变化。

如,删除水印节点:

删除时触发事件,时此会还原节点、重置水印:

如,结点属性被修改(修改display为none使元素不可见,或修改opacity为0使元素完全透明),都会触监听事件,并重置节点属性:

其实应用于产品或项目时,可将JS代码用JShaman进行混淆加密,以防止代码被分析识破从而被针对性的反制。

注:本文演示中是给div添加水印,实际应用此技术时,水印可添加给任意种类的元素内容。

p-watermark.js网页添加水印插件

作者:鹏仔先生

上周五,出差去改上个前端遗留的小问题,用到了watermark.js这个网站添加水印插件,功能很简单,就是给网页添加个水印,我看了下网上,有很多种,基本都是Canvas实现,我想要的是行与行之间交错效果,可是没有找到对应文档,看的烦的...

那就自己简单写个网页添加水印插件吧, tp-watermark.js

身为初级前端,写法比较low,但是功能很完善,请大家多多指导


下载插件:https://qzhan.lanzous.com/iP9effhq7af

DEMO下载:https://qzhan.lanzous.com/i7le1fhq7lg

下载完引入插件

使用水印

RemoveTpWatermark();

删除水印

RemoveTpWatermark();


很方便使用,一列显示几行,一行显示几列都是计算的,大家不用自己定义(具体需要的参数已添加注释)。

	// 添加水印方法
	function TpWatermark(CON,H,W,R,C,S,O) {
		// 判断水印是否存在,如果存在,那么不执行
		if (document.getElementById('tp-watermark') != null) {
			return
		}
		var TpLine = parseInt(document.body.clientWidth/W) * 2; // 一行显示几列
		var StrLine = '';
		for(var i = 0; i < TpLine; i++){
			StrLine += '<span style="display: inline-block; line-height:' + H + 'px; width:' + W + 'px; text-align: center; transform:rotate(' + R + 'deg); color:' + C + '; font-size:'+ S + 'px; opacity:' + O + ';">'+ CON +'</span>'
		}
		var DivLine = document.createElement("div");
			DivLine.innerHTML = StrLine;

		var TpColumn = parseInt(document.body.clientHeight/H) * 2; // 一列显示几行
		var StrColumn = '';
		for(var i = 0; i < TpColumn; i++){
			StrColumn += '<div style="white-space: nowrap;">' + DivLine.innerHTML + '</div>';
		}
		var DivLayer = document.createElement("div");
			DivLayer.innerHTML = StrColumn;
			DivLayer.id = "tp-watermark"; // 给水印盒子添加类名
			DivLayer.style.position = "fixed";
			DivLayer.style.top = "0px"; // 整体水印距离顶部距离
			DivLayer.style.left = "-100px"; // 改变整体水印的left值
			DivLayer.style.zIndex = "99999"; // 水印页面层级
			DivLayer.style.pointerEvents = "none";

		document.body.appendChild(DivLayer); // 到页面中
	}

	// 移除水印方法
	function RemoveTpWatermark(){
		// 判断水印是否存在,如果存在,那么执行
		if (document.getElementById('tp-watermark') == null) {
			return
		}
		document.body.removeChild(document.getElementById('tp-watermark'));
	}


页面需要使用时

	// 执行添加
	TpWatermark('水印','170','400','-20','red','70','.15');
	// TpWatermark(CON,H,W,R,C,S,O); // 值一一对应

CON => 水印文字内容

H => 水印行高

W => 水印宽度

R => 旋转度数(可为负值)

C => 水印字体颜色

S => 水印字体的大小

O => 水印透明度(0~1之间取值)


页面清除水印时

	// 执行移除
	RemoveTpWatermark();

水印行与行之间需要交错显示,需添加css代码(padding-left的交错值,设置的水印宽度的一半即可)

/*通过此样式,控制行与行之间的交错显示  为0则不交错*/
#tp-watermark div:nth-child(2n){
	padding-left: 200px;
}

给鹏仔添加关注,后期版本会更新针对板块来添加水印。

、 代码开发版实现方法

常规代码实现思路是:

1)web 页面加载后,通过 javascript 创建页面元素 div,并在 div 元素中创建文本节点,展示水印内容

2)设置 div 元素样式,将其 zIndex 设置一个较高的值,并设置透明度,实现浮在页面的水印效果

代码开发时需要考虑页面自适应时宽高改变的情况,同时还需要保证不能影响页面的原有事件功能,需要综合考虑的细节比较多。

2、 懒人版实现方法

使用内置水印功能的报表工具,通过简单属性配置完成水印效果。

1)文字水印实现可以通过配置水印属性:

文字要动态变化的话,只需要改为配置表达式就可以啦:

具体操作可以参考 http://c.raqsoft.com.cn/article/1567379764933

实现效果如下图所示:

2)logo 水印在报表工具中的实现也很简单,配置下图片属性就可以了:

具体操作可以参考 http://c.raqsoft.com.cn/article/1571639241616

实现效果如下图所示:

使用报表工具不仅可以快速便捷的实现水印功能,还能给前端工程师带来很多方便之处,例如一些前端效果(数据隔行异色显示、点击表头排序等)可以直接使用工具实现,不用再写前端代码,减少了自己的代码工作量;另外同时也避免了因为需求变更导致的代码重新调整。