当前位置: 首页 > Web前端 > HTML5

前端水印就这么简单

时间:2023-04-05 18:41:17 HTML5

我们想想实现方法。既然我们要做水印,那肯定是全屏的。我们首先会想到几点要用一个div全屏固定。水印需要绑定登录信息,所以我们从cookie中获取账号信息。屏幕上的大水印不如密集的小水印有效。水印前的间距要小一些,以增加覆盖面积。必须有防止篡改的功能。列出以上几点,我们将一一实施。第一点很好地实现了。我们创建一个dom元素并将其插入到主体中。constdivObj=document.createElement('div');conststyleStr=`位置:固定;顶部:0;左:0;底部:0;右:0;z-索引:999999;背景重复:重复;`;divObj.setAttribute('style',styleStr);document.body.appendChild(divObj);我们从cookie中获取第二个水印的内容。constuser=/user_name=([^;]+)/.exec(document.cookie);constname=Array.isArray(user)&&user.length===2&&user[1]?user[1]:'配置水印';这里的name就是我们拿到的用户信息。如果综合考虑第三点和第四点,就用名字做背景图,然后再重复一遍。我们想把文字转成图片,canvas是个不错的选择。同时我们还要考虑到这张图不容易太大(为了满足第三点),所以我们就按照200*100的大小来吧。constcanvasObj=document.createElement('canvas');constcanvas2d=canvasObj.getContext('2d');canvasObj.width=200;canvasObj.height=100;canvas2d.font=fontSize+'pxArial';canvas2d.fillStyle='rgba(128,128,128,.6)';//这里的文字颜色浅一点,以免影响整体美观canvas2d.translate(canvasObj.width/4,canvasObj.height/2);canvas2d.rotate((-30/180)*Math.PI);canvas2d.fillText(名称,0,canvasObj.height/2);//将canvas转换为dataURLconstbase64Url=canvasObj.toDataURL('image/png');现在我们有了一个base64地址就可以作为我们的图片了。第五点是要有防篡改功能。具体来说,我们创建的水印不能被其他人轻易删除。其次,水印的内容不能轻易改变,无论是水印内容还是水印的颜色样式等等。水印内容是因为我们使用了cookie中的登录信息。如果有人更改了cookie中的值,登录信息就会失效,sso端会被强制跳转到登录页面,所以这个可以交给登录系统来做。我们的dom不能轻易删除和改变样式,那么我们需要使用MutationObserverapi,它的作用是监听DOM的变化,并触发回调,我们只需要在回调中重新执行watermark方法就可以避免这种情况问题。if(MutationObserver){letwaterMarkOb=newMutationObserver(function(){const_globalWatermark=document.querySelector(`domId`);//当样式或水印元素dom节点发生变化时,会重绘if((_globalWatermark&&_globalWatermark.getAttribute('style')!==styleStr)||!_globalWatermark){waterMarkOb.disconnect();waterMarkOb=null;setWaterMark();}});//指定观察对象waterMarkOb.observe(document.body,{attributes:true,subtree:true,childList:true,});}最后要注意的一点就是我们的水印功能尽量不要影响业务的使用。所以这里我们要考虑两点:我们的水印dom是在全屏的最上方。虽然级别是99999,但应该不会影响下面元素的运行。所以我们需要增加pointer-events:none属性,不影响鼠标的操作。如果我们想在不更改前端代码的情况下推出水印功能,那么我们就得从服务端入手。比如在nginx中,我们可以使用sub_filter模块来替换返回的文本。例如subs_filter"(<\/body>)""$1"irg;至此我们的水印功能就实现了。一贯的原则,“BB没什么,给我看代码”。整体代码如下:!(function(){//一个配置constoptions={id:'globalWaterMark',fontSize:10,color:'rgba(128,128,128,.6)',rotate:'-30',userName:"Otheridentities"};/***创建水印图片url*/functioncreateWaterMark(){const{fontSize,color,id}=options;constuser=/user_name=([^;]+)/.exec(document.cookie);constname=Array.isArray(user)&&user.length===2&&user[1]?user[1]:options.userName;constcanvasObj=document.createElement('canvas');constcanvas2d=canvasObj.getContext('2d');canvasObj.width=200;canvasObj.height=100;canvas2d.font=fontSize+'pxArial';canvas2d.fillStyle=color;canvas2d.translate(canvasObj.width/4,canvasObj.height/2);canvas2d.rotate((-30/180)*Math.PI);canvas2d.fillText(name,0,canvasObj.height/2);//将画布转换为dataURLconstbase64Url=canvasObj.toDataURL('image/png');返回base64Url;}函数setWaterMark(){const{fontSize,color,id}=options;consturl=createWaterMark();consttarget=document.getElementById(id);if(target){document.body.removeChild(target)}constdivObj=document.createElement('div');divObj.id=options.id;conststyleStr=`位置:固定;顶部:0;左:0;底部:0;右:0;z-索引:999999;重复;指针事件:无;背景图像:url('${url}')`;divObj.setAttribute('style',styleStr);document.body.appendChild(divObj);//监控DOM变化constMutationObserver=window.MutationObserver||window.WebKitMutationObserver;if(MutationObserver){letwaterMarkOb=newMutationObserver(function(){const_globalWatermark=document.querySelector(`#${id}`);//当样式或水印元素的dom节点发生变化时会重新绘制制if((_globalWatermark&&_globalWatermark.getAttribute('style')!==styleStr)||!_globalWatermark){waterMarkOb.disconnect();waterMarkOb=null;设置水印();}});//指定观察对象waterMarkOb.observe(document.body,{attributes:true,subtree:true,childList:true,});}}document.addEventListener('DOMContentLoaded',function(){setWaterMark();});})();