今天用canvas画一个简单的水印
挂载点
const watermarkHookElement = document.body;
// 获取挂载element的几何信息
const rect = watermarkHookElement.getClientRects()[0];
创建canvas
const canvas = document.createElement('canvas');
canvas.width = rect.width;
canvas.height = rect.height;
canvas.style.cssText = 'position: absolute;left: 0;top: 0;z-index: -1;';
watermarkHookElement.appendChild(canvas);
计算水印个数
// 这里的20、50 均可以当做配置项参数
const xCount = rect.width / 20;
const yCount = rect.height / 50;
渲染水印
const ctx = canvas.getContext('2d');
for (let i = 0; i < xCount; i++) {
for (let j = 0; j < yCount; j++) {
ctx.save();
// 重新设置canvas图层的中心点
ctx.translate(i * 140 + 10, j * 70 + 60);
// 单个水印逆时针旋转25度
ctx.rotate(-25 * Math.PI / 180);
ctx.fillStyle = '#ededee';
ctx.font = '16px microsoft yahei';
ctx.fillText('hello world', 0, 0);
ctx.restore();
}
}
关于canvas,可以去看 canvas学习笔记 哦
效果图
resize
每次改变浏览器窗口大小的时候,上面的水印便会拉长或者压缩,加个动态的变化
window.addEventListener('resize', this.drawMark);
防删除
非小白用户总有自己想要干掉水印的冲动,控制台移除canvas节点,水印就木有了,所以对水印加个节点dom的监听,本文用的是MutationObserver
const observer = new MutationObserver(function(records) {
// 这里还可以做些优化, 去判断records的变化类型
this.drawMark();
});
observer.observe(document.body, {
attributes: true,
childList: true,
subtree: true
});
完整代码
写的时候是基于react写的,换其他框架或者原生都是可以的
import React from 'react';
interface IWaterMarkProps {}
interface IWaterMarkState {}
export default class WaterMark extends React.Component<IWaterMarkProps , IWaterMarkState> {
canvas: Element|null;
observer: any;
constructor(props: IWaterMarkProps) {
super(props);
this.canvas = null;
this.drawMark = this.drawMark.bind(this);
}
componentDidMount() {
this.drawMark();
window.addEventListener('resize', this.drawMark);
}
componentWillUnmount() {
this.observer && this.observer.disconnect();
this.canvas && this.canvas.remove();
window.removeEventListener('resize', this.drawMark);
}
drawMark() {
this.canvas && this.canvas.remove();
const watermarkHookElement = document.body;
const rect = watermarkHookElement.getClientRects()[0];
const canvas = document.createElement('canvas');
canvas.width = rect.width;
canvas.height = rect.height;
canvas.style.cssText= 'position: absolute;left: 0;top: 0;z-index: -1;';
watermarkHookElement.appendChild(canvas);
this.canvas = canvas;
const xCount = rect.width / 20;
const yCount = rect.height / 50;
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
for (let i = 0; i < xCount; i++) {
for (let j = 0; j < yCount; j++) {
ctx.save();
ctx.translate(i * 140 + 10, j * 70 + 60);
ctx.rotate(-25 * Math.PI / 180);
ctx.fillStyle = '#ededee';
ctx.font = '16px microsoft yahei';
ctx.fillText('hello world', 0, 0);
ctx.restore();
}
}
this.observer && this.observer.disconnect();
this.observer = new MutationObserver((records) => {
this.drawMark();
});
this.observer.observe(document.body, {
attributes: true,
childList: true,
subtree: true
});
}
render() {
return (
<div></div>
);
}
}
问题
- 在控制台中设置 html canvas { display: none; }, MutationObserver是无法监听到的,水印就被消除了。(虽然可以开定时器,反复添加水印,总感觉有些怪怪的)
- 当有弹窗时或者脱离文档流的内容时,水印被盖在下面了,无法看到,这种情况水印是怎么实现的呢 (监听每个body下所有dom的增添?为每个都增加水印吗?)
关于2 使用z-index: 99999; pointer-events: none; 来解决
看来想写一个通用且安全的水印还需要很多考虑,上面的问题有新的发现时会补充进来
去测试一下你们公司的水印的安全性如何吧~~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。