全站水印功能的核心是通过响应式状态动态控制显示逻辑与内容,并兼顾防截图、复制和DOM篡改。需用Pinia/Vuex管理动态水印配置,Canvas高频重绘+MutationObserver防护,配合后端签名token实现闭环安全。

全站水印功能的核心不是“加一层图片”,而是通过响应式状态动态控制水印的显示逻辑与内容,同时兼顾安全防护——防止截图、复制、恶意篡改DOM。关键在于:水印要随用户身份、页面状态实时变化,且不能被轻易移除或绕过。
用响应式状态驱动水印内容与可见性
水印不应是静态CSS背景图,而应基于当前用户状态(如登录态、角色、设备类型、访问时间)动态生成。例如:
- 使用 Pinia 或 Vuex 管理全局水印状态,如 watermarkConfig = { visible: true, text: `${user.name} | ${user.org} | ${Date.now()}` }
- 在根组件(如 App.vue)中监听该状态,用 v-if 控制水印容器渲染,避免无意义 DOM 节点残留
- 对敏感页面(如后台、数据看板),在路由守卫中自动更新水印文本,加入页面路径和时间戳,增强溯源能力
防截屏 & 防篡改的 DOM 层水印方案
纯 CSS 背景水印易被截图工具绕过,也容易被开发者工具删除。更可靠的方案是:用 Canvas 动态绘制半透明文字,并以固定频率重绘(防 DOM 删除):
- 创建一个全屏定位、pointer-events: none 的 canvas 元素,z-index 设为最高层但低于弹窗
- 利用 requestAnimationFrame 每 200ms 重绘一次,每次微调文字角度或位置(防 OCR 批量识别)
- 监听 document.body.children 变化,若检测到水印节点被移除,立即重建 —— 这需要 MutationObserver 配合响应式状态判断是否应启用防护
服务端协同增强安全性
前端水印可被禁用或绕过,必须配合后端策略形成闭环:
- 前端在初始化水印时,向后端请求一个带签名的水印 token(含用户 ID、时间戳、随机 nonce),后端校验并返回加密后的水印文本片段
- 将 token 存入 pinia state 并设为不可响应式(markRaw),防止被 Vue Devtools 修改
- 后端日志记录每次水印 token 的生成与页面访问行为,异常高频请求或 token 失效即触发告警
规避常见失效场景
很多水印方案上线后形同虚设,问题多出在细节:
- 不要用 base64 图片作为水印背景 —— 可被一键提取、替换;优先用 Canvas 或 SVG 动态生成
- 避免固定 ID 或 class 名称(如 #watermark)—— 改为动态生成哈希类名,配合 CSS-in-JS 或 scoped style 隐藏选择器痕迹
- 移动端需单独适配 —— 触摸事件可能遮挡水印,建议在 viewport 变化时重新计算 canvas 布局与字体大小










