内容简介:为了防止信息泄露,保障信息安全,给网页添加水印是一种比较常见的方法。本文介绍一种添加水印的方法,具有以下特点:思考一下,生成的水印需要满足那些需求呢?
为了防止信息泄露,保障信息安全,给网页添加水印是一种比较常见的方法。
本文介绍一种添加水印的方法,具有以下特点:
- 不影响现有代码
- 可以任意给网页的不同部分添加水印
- 纯前端 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的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
程序员代码面试指南:IT名企算法与数据结构题目最优解(第2版)
左程云 / 电子工业出版社 / 109.00元
《程序员代码面试指南:IT名企算法与数据结构题目最优解(第2版)》是一本程序员代码面试"神书”!书中对IT名企代码面试各类题目的最优解进行了总结,并提供了相关代码实现。针对当前程序员面试缺乏权威题目汇总这一痛点,本书选取将近300道真实出现过的经典代码面试题,帮助广大程序员的面试准备做到接近万无一失。"刷”完本书后,你就是"题王”!《程序员代码面试指南:IT名企算法与数据结构题目最优解(第2版)》......一起来看看 《程序员代码面试指南:IT名企算法与数据结构题目最优解(第2版)》 这本书的介绍吧!