从以下几点判断水印消失:
1.选用canvas 防止水印内容篡改
2.选用MutationObserver 监听水印的style属性是否被篡改和监听水印元素是否被删除
3.定时更新元素的z-index动态计算最大层级
watermark.js
javascript
let obj = JSON.parse(window.localStorage.getItem("User"));
let watermarkUrl = createWatermark([obj.name, obj.account]);
function createWatermark (text = '默认水印') {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸
canvas.width = 200;
canvas.height = 150;
// 旋转文字
ctx.rotate((-15 * Math.PI) / 180);
// 设置文字样式
ctx.font = '20px Microsoft YaHei';
ctx.fillStyle = 'rgba(0, 0, 0,0.1)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// 绘制文字(支持多行)
const texts = Array.isArray(text) ? text : [text];
texts.forEach((line, i) => {
ctx.fillText(line, canvas.width / 2, canvas.height / 2 + i * 20);
});
// 转为图片URL
return canvas.toDataURL('image/png');
}
// 计算页面中最大的z-index
function getMaxZIndex () {
// 获取所有可见元素
const elements = document.querySelectorAll('body *:not(.watermark-layer)');
let maxZ = 10; // 默认最低层级(确保至少高于普通内容)
elements.forEach(el => {
const position = window.getComputedStyle(el).position;
// 只处理有定位的元素(z-index对static无效)
if (position !== 'static') {
const zIndex = window.getComputedStyle(el).zIndex;
if (zIndex !== 'auto') {
const z = parseInt(zIndex, 10);
if (!isNaN(z) && z > maxZ) {
maxZ = z;
}
}
}
});
return maxZ;
}
let styleStr = `position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url(${watermarkUrl});
background-repeat: repeat;
pointer-events: none;
z-index: ${getMaxZIndex() + 1};
`
// 闭包封装水印防护逻辑
export function initWatermark () {
console.log('创建元素');
// 创建水印元素(初始层级为最大z-index +1)
let watermarkEl = document.createElement('div');
watermarkEl.className = 'watermark-layer';
watermarkEl.style.cssText = styleStr
document.body.appendChild(watermarkEl);
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
const watermarkEl = document.querySelector('.watermark-layer');
if (!watermarkEl) {
console.log('水印被删除,重新创建')
observer.disconnect();
initWatermark();
}
if (mutation.attributeName === 'style' && watermarkEl && watermarkEl.getAttribute('style') !== styleStr) {
// 样式变化时,重新设置
console.log('样式变化时,重新设置', styleStr)
watermarkEl.setAttribute('style', styleStr);
}
});
});
observer.observe(document.body, {
attributes: true,
childList: true,
subtree: true,
});
// 定时检查zIndex
const checkTimer = setInterval(() => {
zIndex();
}, 300)
// 清理函数
return () => {
observer.disconnect();
clearInterval(checkTimer);
};
}
// 层级
function zIndex () {
styleStr = `position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url(${watermarkUrl});
background-repeat: repeat;
pointer-events: none;
z-index: ${getMaxZIndex() + 1};
`
const watermarkEl = document.querySelector('.watermark-layer');
watermarkEl.setAttribute('style', styleStr);
}
main.vue
javascript
import { initWatermark } from '@/utils/watermark'; //引入
export default {
data(){
return{
watermarkCleanup: null,
}
}
created(){
//创建水印并保存清理函数
const watermarkEl = document.querySelector('.watermark-layer');
if (!watermarkEl) {
// 保存清理函数的引用
this.watermarkCleanup = initWatermark();
}
}
beforeDestroy () {
// 调用清理函数来关闭定时器和页面元素监听
if (this.watermarkCleanup) {
this.watermarkCleanup();
}
}
}
如有遗漏,欢迎指教补充