UNPKG

xxm-test-js

Version:
276 lines 10 kB
"use strict"; /** * 页面水印类 * * 使用场景:为页面添加水印,用于版权保护、信息安全、防止截图泄密等场景。 * 适用于后台管理系统、敏感信息页面、文档预览等需要标识用户身份或保护内容的场合。 * * 主要特性: * - 自定义水印内容:支持单行或多行文字 * - 样式配置:可配置字体、颜色、大小、透明度、旋转角度等 * - 防删除保护:使用 MutationObserver 监听 DOM 变化,防止水印被删除或修改 * - 高性能:使用 Canvas 生成水印,以 base64 图片作为背景 * - 响应式:支持窗口大小变化时自动调整 * - 易于销毁:提供销毁方法,完全清理水印和监听器 * * @example * ```typescript * // 基本用法 * const watermark = new Watermark({ * content: '机密文档', * fontSize: 16, * opacity: 0.15 * }); * watermark.create(); * * // 多行水印 * const watermark = new Watermark({ * content: ['张三', '2024-01-01', '仅供内部使用'], * color: '#000', * rotate: -20 * }); * watermark.create(); * * // 销毁水印 * watermark.destroy(); * ``` */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Watermark = void 0; class Watermark { constructor(options = {}) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; this.watermarkElement = null; this.observer = null; this.resizeObserver = null; this.isDestroyed = false; this.options = { content: (_a = options.content) !== null && _a !== void 0 ? _a : '水印', container: (_b = options.container) !== null && _b !== void 0 ? _b : document.body, width: (_c = options.width) !== null && _c !== void 0 ? _c : 200, height: (_d = options.height) !== null && _d !== void 0 ? _d : 150, fontSize: (_e = options.fontSize) !== null && _e !== void 0 ? _e : 16, fontStyle: (_f = options.fontStyle) !== null && _f !== void 0 ? _f : 'normal', fontWeight: (_g = options.fontWeight) !== null && _g !== void 0 ? _g : 'normal', fontFamily: (_h = options.fontFamily) !== null && _h !== void 0 ? _h : 'Microsoft YaHei, sans-serif', color: (_j = options.color) !== null && _j !== void 0 ? _j : '#000000', opacity: (_k = options.opacity) !== null && _k !== void 0 ? _k : 0.15, rotate: (_l = options.rotate) !== null && _l !== void 0 ? _l : -20, zIndex: (_m = options.zIndex) !== null && _m !== void 0 ? _m : 9999, lineHeight: (_o = options.lineHeight) !== null && _o !== void 0 ? _o : 20, monitor: (_p = options.monitor) !== null && _p !== void 0 ? _p : true, id: (_q = options.id) !== null && _q !== void 0 ? _q : 'watermark-container', }; } /** * 创建水印 */ create() { if (this.isDestroyed) { console.warn('水印已被销毁,无法创建'); return; } // 如果已存在水印,先删除 this.removeWatermarkElement(); // 创建水印元素 this.watermarkElement = this.createWatermarkElement(); this.options.container.appendChild(this.watermarkElement); // 启动监听 if (this.options.monitor) { this.startMonitor(); } // 监听窗口大小变化 this.observeResize(); } /** * 更新水印配置 * @param options 新的配置项 */ update(options) { var _a; if (this.isDestroyed) { console.warn('水印已被销毁,无法更新'); return; } // 更新配置 this.options = Object.assign(Object.assign(Object.assign({}, this.options), options), { container: (_a = options.container) !== null && _a !== void 0 ? _a : this.options.container }); // 重新创建水印 this.create(); } /** * 销毁水印 */ destroy() { this.isDestroyed = true; this.stopMonitor(); this.stopResizeObserver(); this.removeWatermarkElement(); } /** * 创建水印元素 */ createWatermarkElement() { const div = document.createElement('div'); div.id = this.options.id; // 设置样式 Object.assign(div.style, { position: 'absolute', top: '0', left: '0', width: '100%', height: '100%', pointerEvents: 'none', zIndex: String(this.options.zIndex), backgroundImage: `url(${this.generateWatermarkImage()})`, backgroundRepeat: 'repeat', }); return div; } /** * 生成水印图片(base64) */ generateWatermarkImage() { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('无法获取 Canvas 上下文'); } canvas.width = this.options.width; canvas.height = this.options.height; // 设置旋转 ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate((this.options.rotate * Math.PI) / 180); ctx.translate(-canvas.width / 2, -canvas.height / 2); // 设置字体样式 ctx.font = `${this.options.fontStyle} ${this.options.fontWeight} ${this.options.fontSize}px ${this.options.fontFamily}`; ctx.fillStyle = this.options.color; ctx.globalAlpha = this.options.opacity; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; // 绘制文字 const content = Array.isArray(this.options.content) ? this.options.content : [this.options.content]; const startY = canvas.height / 2 - ((content.length - 1) * this.options.lineHeight) / 2; content.forEach((text, index) => { const y = startY + index * this.options.lineHeight; ctx.fillText(text, canvas.width / 2, y); }); return canvas.toDataURL(); } /** * 移除水印元素 */ removeWatermarkElement() { if (this.watermarkElement && this.watermarkElement.parentNode) { this.watermarkElement.parentNode.removeChild(this.watermarkElement); this.watermarkElement = null; } else { // 尝试通过 ID 查找并删除 const existingElement = document.getElementById(this.options.id); if (existingElement && existingElement.parentNode) { existingElement.parentNode.removeChild(existingElement); } } } /** * 启动 DOM 监听(防删除) */ startMonitor() { if (!this.options.monitor || this.isDestroyed) { return; } this.stopMonitor(); this.observer = new MutationObserver((mutations) => { if (this.isDestroyed) { return; } let shouldRecreate = false; mutations.forEach((mutation) => { // 检查是否删除了水印元素 if (mutation.type === 'childList') { mutation.removedNodes.forEach((node) => { if (node === this.watermarkElement || (node instanceof HTMLElement && node.id === this.options.id)) { shouldRecreate = true; } }); } // 检查是否修改了水印元素的属性或样式 if (mutation.type === 'attributes' && mutation.target === this.watermarkElement) { shouldRecreate = true; } }); if (shouldRecreate) { this.create(); } }); // 监听容器的子节点变化和属性变化 this.observer.observe(this.options.container, { childList: true, attributes: true, subtree: true, attributeFilter: ['style', 'class'], }); // 监听水印元素本身 if (this.watermarkElement) { this.observer.observe(this.watermarkElement, { attributes: true, attributeFilter: ['style'], }); } } /** * 停止 DOM 监听 */ stopMonitor() { if (this.observer) { this.observer.disconnect(); this.observer = null; } } /** * 监听容器大小变化 */ observeResize() { if (typeof ResizeObserver === 'undefined') { // 降级到 window resize 事件 this.handleResize = this.handleResize.bind(this); window.addEventListener('resize', this.handleResize); return; } this.stopResizeObserver(); this.resizeObserver = new ResizeObserver(() => { if (!this.isDestroyed && this.watermarkElement) { // 容器大小变化时,更新水印元素的大小 this.watermarkElement.style.width = '100%'; this.watermarkElement.style.height = '100%'; } }); this.resizeObserver.observe(this.options.container); } /** * 停止监听容器大小变化 */ stopResizeObserver() { if (this.resizeObserver) { this.resizeObserver.disconnect(); this.resizeObserver = null; } else { window.removeEventListener('resize', this.handleResize); } } /** * 处理窗口大小变化(降级方案) */ handleResize() { if (!this.isDestroyed && this.watermarkElement) { this.watermarkElement.style.width = '100%'; this.watermarkElement.style.height = '100%'; } } } exports.Watermark = Watermark; //# sourceMappingURL=Watermark.js.map