水印
const init = Symbol('init');
export default class WaterMask {
[init] = () => {
const {
container = document.body,
isRem = true,
content = '01211115',
width = '160px',
color = '#97989C',
height = '180px',
opacity = '0.2',
fontSize = '14px',
zIndex = 1000,
} = this.options;
document.documentElement.style.height = '100%';
function pxRemScale(size) {
return isRem
? (size.replace('px', '') / 16) *
(document.documentElement.style.fontSize.replace('px', '') || 14) *
1 +
'px'
: size;
}
const svgStr = `<svg xmlns="http://www.w3.org/2000/svg" width="${pxRemScale(
width,
)}" height="${pxRemScale(height)}">
<text x="50%" y="50%" dy="12px"
text-anchor="middle"
fill="${color}"
fill-opacity="${opacity}"
transform="rotate(-45, 120 120)"
style="font-size: ${pxRemScale(fontSize)};">
${content}
</text>
</svg>`;
const base64Url = `data:image/svg+xml;base64,${window.btoa(
unescape(encodeURIComponent(svgStr)),
)}`;
const waterMask = document.querySelector('.water-mask');
const watermarkDiv = waterMask || document.createElement('div');
watermarkDiv.className = 'water-mask';
watermarkDiv.setAttribute(
'style',
`position:absolute;
top:0;
left:0;
width:${document.documentElement.offsetWidth}px;
height:${document.documentElement.offsetHeight}px;
z-index:${zIndex};
pointer-events:none;
background-repeat:repeat;
background-position:0;
background-image:url('${base64Url}')`,
);
container.style.position = 'relative';
container.appendChild(watermarkDiv);
this.bindMutationOberve();
this.bindWindowResizeEvent();
};
constructor(
options = {
container: document.body,
isRem: false,
content: '请勿外传',
width: '300px',
height: '200px',
opacity: '0.2',
fontSize: '28px',
zIndex: 1000,
},
) {
this.options = options;
this[init]();
}
bindWindowResizeEvent = () => {
window.addEventListener('resize', this.adjust);
};
adjust = () => {
window.requestAnimationFrame(() => {
const watermarkDiv = document.querySelector('.water-mask');
watermarkDiv.style.width = `${document.documentElement.offsetWidth}px`;
watermarkDiv.style.height = `${document.documentElement.offsetHeight}px`;
});
};
bindMutationOberve = () => {
let config = {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeOldValue: true,
characterDataOldValue: true,
};
const mutationCallback = mutationList => {
for (let mutation of mutationList) {
let type = mutation.type;
switch (type) {
case 'childList':
if (!document.querySelector('.water-mask')) {
console.log('水印节点被移除,上报服务器或警告');
}
break;
case 'attributes':
if (!document.querySelector('.water-mask')) {
console.log('水印节点被移除,上报服务器或警告');
}
break;
case 'subtree':
console.log('子树被修改');
break;
default:
console.log(type);
break;
}
}
};
// 创建 MutationObserver 实例
this.observer = new MutationObserver(mutationCallback);
// 开始监控目标节点
this.observer.observe(document.body, config);
};
destroy = () => {
const watermarkDiv = document.querySelector('.water-mask');
watermarkDiv.remove();
window.removeEventListener('resize', this.adjust);
this.observer.disconnect();
};
}
- 首先声明一个WaterMask类,通过这个类生成一个实例化对象,在初始化实例对象时,传一些必要属性;比如:水印内容,根元素(document.body),水印样式,透明度等。
- 函数
pxRemScale
是用于适配性修改字体大小,此处用到rem
单位,即相对于根元素的字体大小进行比例缩放; - 生成一个svg图片对象,然后手动生成一个
base64
的图片,生成一个div
元素,然后将该图片作为背景图片,设置绝对定位定位属性postition:abosulte
;background-repeat:repeat该属性可以将文本重复渲染到全屏; - 设置body元素
position
属性,然后将div
元素加入body中,此时让div
元素充满整个body,并且设置最高的层级z-index
,需要注意的是,此时整个应用有一层透明蒙层在,需要设置pointer:none
,设置事件穿透效果; - 创建 MutationObserver 实例,用于监听
div
元素的改动,如果改动就进行恢复或者警示; - 【注意:MutationObserver 是一个微任务】
this.observer = new MutationObserver(mutationCallback);
- 最后可以设置一个
水印销毁方法
,可配置化的设置水印; - 监听
this.observer.observe(document.body, config);
- 取消监听:
this.observer.disconnect();
总结
1.生成一个svg对象,这个对象可以作为
新建元素div的背景图片
;
2.将该div元素
放在根元素中,通过设置position:absolute
属性让元素充满整个body;注意:绝对定位元素会脱离文档流,因此可以铺满整个父元素
,设置较高的层级值z-index
,但是需要设置透明属性,以及pointer:none
,事件穿透效果;
3.获取根元素的fontsize
,用rem
动态的设置字体大小,保证字体的适配性;
4.创建MutationObserver
实例监听div
元素的改动,如果改动则恢复设置或者警示;
5.使用方法,初始化一个水印实例对象,初始化的时候将必要的参数传入,给到div
元素使用,比如:水印内容,蒙层透明度,根元素,样式等
知识点
- position定位
- 元素的添加,移除,设置事件穿透,
background-repeat:repeat
重复渲染铺满全屏; - 根元素的
fontsize
,rem单位
适配性问题,px,em
区别; - 创建
MutationObserver
实例监听div元素的改动,微任务;
参考:前端生成水印方法
https://mp.weixin.qq.com/s/-FVRx0uwq2UUsXuJty6OIg