背景:在开发移动端内部应用的时候,涉及安全问题,我们经常在企业微信或者图片上看到水印,防止信息被泄露,针对这次开发做个复盘,记录下。
效果图如下:
一、实现原理
- 1、首先用canvas绘制水印
- 2、创建蒙层div,可以覆盖在页面上,并设置pointer-events:none属性
- 3、将canvas绘制的水印作为背景图重复渲染在第二步创建的div上
- 4、将第三步水印div插入容器中
二、组件封装
1、新建移动端项目,具体见构建方法
2、定义组件接收的参数,包括水印覆盖的样式和文本内容
import PropTypes from 'prop-types'
WaterMark.propTypes = {
className: PropTypes.string,
txt: PropTypes.string,
restProps: PropTypes.object
}
WaterMark.defaultProps = {
txt: "watermark"
}
3、创建容器,将需要打水印的页面包含其中
<div
className={`watermark_wrapper ${className ? `${className}` : ""}`}
style={{ position: "relative" }}
{...restProps}
>
{children}
</div>
4、canvas绘制水印
这里设置水印大小,文字样式,旋转角度等,最终返回一个canvas。
const generateWaterLog = (content) => {
const canvas = document.createElement("canvas");
canvas.setAttribute("width", "100px");
canvas.setAttribute("height", "100px");
const ctx = canvas.getContext("2d");
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fontSize = 24;
ctx.fillStyle = "rgba(184, 184, 184, 0.8)";
ctx.rotate(-(Math.PI / 180) * 30);
ctx.fillText(content, 100 / 2, 100 / 2);
return canvas
}
5、创建蒙层将上一步绘制的水印放在上面
设置蒙层div通过绝对定位放在文本表面,将canvas转化成base64,作为背景图重复渲染在蒙层上。 这样设置会导致,页面服务点击操作,这时候要设置 pointer-events: none; 让蒙层鼠标事件失效。这样不影响实际内容的操作。
const generateWaterMark = (canvas) => {
const bg_url = canvas.toDataURL()
const waterMarkDiv = document.createElement("div");
const style = `
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
pointer-events: none;
background-repeat: repeat;
background-image: url('${bg_url}')
`;
waterMarkDiv.setAttribute("style", style);
waterMarkDiv.setAttribute("class", "watermark-bg");
return waterMarkDiv
}
6、渲染水印
生成了蒙层,并且渲染了水印,调用生成水印函数,获取要渲染水印的容器,并给其中插入水印div, 这里要排除下节点className为水印蒙层的div
generateTextWatermark(txt, document.body.querySelectAll(".watermark_wrapper"))
const generateTextWatermark = (content, container) => {
const canvas = generateWaterLog(content)
const waterMarkDiv = generateWaterMark(canvas)
Array.from(container).forEach((node) => {
if (!node.getElementsByClassName("watermark-bg").length) {
node.appendChild(waterMarkDiv.cloneNode(true));
}
});
};
7、调用
import { WaterMark } from "../../components"
<WaterMark>
<div>需要添加水印的文本</div>
</WaterMark>
三、demo示例
yarn安装
yarn add demo-ui
npm安装
npm install -S demo-ui
使用
import React from "react";
import { WaterMark } from 'demo-ui'
function Demo() {
return (
<WaterMark>
<div className="padding10 font-size-14 demo">
<h2 className="text-center font-size-16">水印DEMO</h2>
<header className="text-indent-2">
本协议将对用户使用本产品的行为产生法律约束力,您已承诺和保证有权利和能力订立本协议。用户开始使用本产品将视为已经接受本协议,请认真阅读并理解本协议中各种条款,包括免除和限制我们的免责条款和对用户的权利限制(未成年人审阅时应由法定监护人陪同),如果您不能接受本协议中的全部条款,请勿开始使用本产品。
</header>
<div>
<h4>一、使用账户</h4>
<p className="text-indent-2">
您必须承诺和保证: 1. 您使用本产品的行为必须合法
本产品将会依据本协议“修改和终止”的规定保留或终止您的账户。您必须承诺对您的登录信息保密、不被其他人获取与使用,并且对您在本账户下的所有行为负责。您必须将任何有可能触犯法律的、未授权使用或怀疑为未授权使用的行为在第一时间通知本产品。本产品不对您因未能遵守上述要求而造成的损失承担法律责任。
</p>
</div>
</div>
</WaterMark>
);
}
export default Demo;