内容简介:为了防止信息泄露,保障信息安全,给网页添加水印是一种比较常见的方法。本文介绍一种添加水印的方法,具有以下特点:思考一下,生成的水印需要满足那些需求呢?
为了防止信息泄露,保障信息安全,给网页添加水印是一种比较常见的方法。
本文介绍一种添加水印的方法,具有以下特点:
- 不影响现有代码
- 可以任意给网页的不同部分添加水印
- 纯前端 JavaScript 实现
- 可简单防止用户通过浏览器开发者 工具 隐藏水印
思考一下,生成的水印需要满足那些需求呢?
- 根据动态内容生成静态图片
- 包含一段标识信息,同时需要覆盖足够的区域
根据水印的需求,自然会想到用 background
指定 image
,并让其在 x,y 方向上重复展示,来实现覆盖区域。那么如何根据动态内容生成 image
?你一定可以想到前端的绘图魔法(Canvas / SVG)。首先绘制好我们需要的图形,拿到图形编码后的 Data URLs
字符串,该字符串包含所需的图像信息,再配合使用 background
属性实现给网页添加水印。
绘图魔法(一)—— Canvas
HTMLCanvasElement.toDataURL 该方法返回一个包含图片信息的 Data URLs。
const canvas = document.createElement('canvas'); canvas.setAttribute('width', width); canvas.setAttribute('height', height); var ctx = canvas.getContext("2d"); ctx.textAlign = textAlign; ctx.textBaseline = textBaseline; ctx.font = font; ctx.fillStyle = fillStyle; ctx.rotate(Math.PI / 180 * rotate); ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2); var base64Url = canvas.toDataURL();
绘图魔法(二)—— SVG
SVG:可缩放矢量图形是一种基于可扩展标记语言,用于描述二维矢量图形的图形格式。使用 SVG 生成图片的方式和 Canvas 的方式类似,只是 Data URLs 的生成方式换成了 SVG。
const svgStr = `<svg xmlns="namespace" width="${width}" height="${width}"> <text x="50%" y="50%" dy="12px" text-anchor="middle" stroke="#000000" stroke-width="1" stroke-opacity="${opacity}" fill="none" transform="rotate(-45, 120 120)" style="font-size: ${fontSize};"> ${content} </text> </svg>`; const base64Url = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgStr)))}`;
生成 Data URLs 之后,可将其存为全局变量或者存在 store 中,方便随时可取且保证生成一次。通过阅读前文已经知道,水印是可以通过在 DOM 节点上添加 background-image
, background-repeat
属性来实现的。那么如何给目标节点添加 background-image
属性呢?来看看 Vue、React 项目中如何实现的吧。下文提到的 imageURI
为上文提到的 Data URLs。
Vue
1.自定义指令,在需要打上水印的节点上添加 v-watermarked
指令
Vue.directive('watermarked', { bind(el, binding, vnode) { if (binding.value === undefined || !!binding.value) { el.style.backgroundImage = imageURI ; el.style.backgroundRepeat = 'space repeat'; /* 顺手提一波 background-repeat:space repeat; 图像在水平方向上尽可能重复,但不会被裁剪,第一个和最后一个图像会被固定在远足的相应的边上,同时空白会均匀地分布在图像之间。图像在垂直方向上重复来覆盖整个区域,若大小不合适可被剪裁 */ } }, update(el, binding, vnode) { if (binding.value === undefined || !!binding.value) { el.style.backgroundImage = imageURI; el.style.backgroundRepeat = 'space repeat'; } }, });
2.封装组件,在需要打上水印的节点外层包上 <watermark>...</watermark>
<template> <div class="watermark" :style="{ backgroundRepeat: 'space repeat', backgroundImage:imageURI, }"> <slot /> </div> </template>
react
1.封装组件
<Watermark> ... </Watermark> // 或者使用 render props <Watermark> {({blob}) => ( ... )} </Watermark>
2.直接写进组件样式里面
// 以 styled-components 为例 import styled from 'styled-components'; const Root = styled.div` ${watermark()} `
3.高阶组件
@Watermark class Page extends React.Component { ... }
现在你已经大概了解如何给页面打上水印了,你发现有什么问题了吗?其实这存在一个弊端,用户通过开发者工具动态更改 DOM 属性或者结构,就可以轻松删除掉水印。那么我们该如何阻止该行为呢?
MutationObserver
MutationObserver 给开发者们提供了能在某个范围内的 DOM 树发生变化时作出适当反应的能力。
使用 MutationObserver 构造函数,新建一个观察器实例,实例的有一个回调函数,该回调函数接受两个参数,第一个是变动数组(包含一系列变动记录 MutationRecord
),第二个是观察器实例。 MutationObserver
的实例的 observe
方法用来启动监听,它接受两个参数。第一个参数:所要观察的 DOM 节点,第二个参数:一个配置对象,指定所要观察的特定变动( config
)。
MutationObserver 只能监测到诸如属性改变,增删子节点等,但需要注意的是对于自己本身被删除,是没有办法的,可以用过监测父节点来达到要求。
写个例子吧,可以在监听到用户删除 style
属性操作,及时恢复水印。
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver; const config = { attributes: true, //观察受监视元素的属性值更改 attributeOldValue: true, // 记录任何有改动的属性的上一个值 }; const callback = (mutationList, observer) => { /*mutationList包含一系列变动记录*/ _.forEach(mutationList, (mutationRecord) => { const { type, attributeName } = mutationRecord; /* type 更改类型 attributeName 返回被修改属性的属性名 */ if (type === 'attributes' && attributeName === 'style') { observer.disconnect(); //先停止监听 否则会不断触发 const { target, oldValue } = mutationRecord; /* target 为受监视元素 oldValue 被更改属性值的旧值 */ target.setAttribute('style', oldValue); observer.observe(target, config); // 修改完后恢复监听 } }); }; Vue.directive('watermarked', { bind(el, binding, vnode) { if (binding.value === undefined || !!binding.value) { el.style.backgroundImage = imageURI; el.style.backgroundRepeat = 'space repeat'; const om = new MutationObserver(callback); om.observe(el, config); } }, });
这里提供两个demo,以供参考。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Python+OpenCV为图片添加中文水印与图片水印
- 工具系列--简单水印(watermark-dom)和算法水印(频域方式图片合并)实现
- 插件系列--简单水印(watermark-dom)和算法水印(频域方式图片合并)实现
- 前端页面水印生成实现
- 浅谈前端水印
- 网页水印SDK的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Code Reading
Diomidis Spinellis / Addison-Wesley Professional / 2003-06-06 / USD 64.99
This book is a unique and essential reference that focuses upon the reading and comprehension of existing software code. While code reading is an important task faced by the vast majority of students,......一起来看看 《Code Reading》 这本书的介绍吧!