/** 水印指令
- 要求父元素position至少是relative、 fixed、 absolute其中一种
- binding中可选的参数:和canvasWM中保持一致 / export default { /* 更新时 */ update(el: any, binding: any): void { // 获取绑定的参数 const { value }: any = binding; if (value) { if (typeof value === 'object') { if (typeof value.show === 'undefined' || value.show) { canvasWM({ container: el, ...value }); } else { canvasWM({ container: el, ...value, clear: true }); } } } else { canvasWM(); } } };
// 保存每个指令的observer const wmMutationObserverMap = new Map(); // 保存内容 const wmContentMap = new Map(); // 保存每个指令的是否显示参数 const paramsMap = new Map();
/** 生成图片
-
container:生成元素的对象
-
show:是否显示
-
clear:是否清除元素 */ function canvasWM({ container = document.body, width = '300px', height = '300px', font = '24px Microsoft Yahei', fillStyle = 'rgba(220, 220, 220, 0.3)', content = '', rotate = -30, show = true, clear = false }: any = {}): any { let id = container.id; if (!id) { id =
wm_${new Date().getTime()}; container.setAttribute('id', id); }paramsMap.set(id, show); wmContentMap.set(id, content); // 监听元素变化,防止生成重复的监听器 let observer: any = wmMutationObserverMap.get(id); let styleStr: any = null; // 删除元素 if (clear) { clearWM(container);
return;}
/** 生成水印 */ // eslint-disable-next-line func-names, require-jsdoc const createWM = function (): void { // 生成canvas元素 const canvas: HTMLCanvasElement = document.createElement('canvas'); canvas.setAttribute('width', width); canvas.setAttribute('height', height); // 获取画板上下文 const ctx: any = canvas.getContext('2d'); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = font; ctx.fillStyle = fillStyle; // 旋转 ctx.rotate((rotate * Math.PI) / 180); content = content || wmContentMap.get(id); ctx.fillText(content, 20, parseFloat(height));
const base64Url = canvas.toDataURL(); const wm = container.querySelector('.watermarker'); const watermarkDiv = wm || document.createElement('div'); styleStr = ` position:absolute; top:0; left:0; bottom:0; right:0; width:100%; height:100%; color:rgba(0,0,0,.75); z-index:2000; pointer-events:none; background-repeat:repeat; background-image:url('${base64Url}')`; watermarkDiv.setAttribute('style', styleStr); watermarkDiv.classList.add('watermarker'); if (!wm) { container.insertBefore(watermarkDiv, container.firstChild); }};
// 此方法是防止用户通过 修改样式或直接删除 if (!observer) { observer = new MutationObserver((mutationList: any) => { const showWM = paramsMap.get(id); const wmInstance = container.querySelector('.watermarker'); // 获取到你的水印dom // 防止被删除 if (!wmInstance && showWM) { console.log('水印被删除了!!!'); createWM(); // 防止下面的样式事件触发
return; } // 防止样式被改 if (wmInstance?.getAttribute('style') !== styleStr && showWM) { console.log('改水印样式了!!!'); createWM(); return; } // // 防止类被改 // if (mutationList?.[0].attributeName === 'class' && showWM) { // console.log(mutationList); // console.log('改水印样式类了!!!'); // clearWM(container); // createWM(); // } }); observer.observe(container, { childList: true, // 观察目标子节点的变化,是否有添加或者删除 attributes: true, // 观察属性变动 subtree: true // 观察后代节点,默认为 false }); wmMutationObserverMap.set(id, observer);}
/** 清除水印 */ function clearWM(el: HTMLElement): void { const wms = el.querySelectorAll('.watermarker'); wms.forEach((wm) => wm.remove()); }
createWM(); }