pinia 通过 usewatermarkstore 统一管理水印配置(visible、text、color 等),封装 actions 控制更新,联动 canvas 重绘、路由守卫、登录态同步及 sessionstorage 持久化,并结合 v-if、mutationobserver 和动态类名增强防绕过能力。

Pinia 管理页面水印的全局状态,核心是把水印配置(如是否显示、文字内容、颜色、透明度、字体大小等)作为响应式数据统一存入 Store,并让所有相关逻辑(Canvas 绘制、DOM 监听、路由切换响应)基于该状态自动更新。
定义水印 Store:集中管理可变配置
创建一个 useWatermarkStore,用 state 保存动态参数,actions 提供安全可控的修改入口:
-
state 包含基础字段:如
visible: true、text: ''、color: 'rgba(0,0,0,0.08)'、fontSize: 14、angle: -25、gapX: 120、gapY: 120 -
避免直接暴露原始 state 修改:不鼓励组件中直接写
store.text = 'xxx',而是通过actions封装逻辑,例如updateText(user, page)自动拼接${user.name} | ${page} | ${Date.now()} -
敏感字段做保护:如后端返回的签名 token,用
markRaw()包裹,防止被 Vue Devtools 意外修改或响应式劫持
联动 Canvas 绘制:响应式触发重绘
根组件(如 App.vue)监听 Store 状态变化,一旦 visible 或 text 等关键字段变更,立即触发 Canvas 重绘函数:
-
使用
watch监听整个state或关键 getter,例如watch(() => store.$state, renderWatermark, { deep: true }) -
重绘逻辑不耦合 Store:把绘制封装为独立函数
renderWatermark(canvas, config),只接收 plain object 参数,便于测试和复用 - 配合 requestAnimationFrame 防止卡顿:高频更新时节流绘制,比如每 200ms 最多重绘一次,同时微调角度或位置增强防识别能力
按需激活与上下文感知
水印不是全站恒定不变的,应随用户身份、路由、权限实时调整:
-
在路由守卫中更新:进入敏感页(如
/admin、/data/report)时,调用store.updateConfig({ text: `${user.id}-${to.path}-${Date.now()}` }) -
登录态变化时同步刷新:用户登录/登出后,
useAuthStore的 action 内部调用useWatermarkStore().syncWithUser(authState) -
支持 sessionStorage 持久化配置:管理员在系统设置页修改水印样式后,存入
sessionStorage,页面刷新后由 Store 自动读取恢复
防绕过设计:状态驱动防护行为
水印的安全性不仅靠视觉,更依赖状态与 DOM 行为的强绑定:
-
用
v-if="watermarkStore.visible"控制 canvas 容器渲染,而非仅靠v-show或 CSSdisplay:none,避免残留 DOM 节点被手动删除 -
MutationObserver 响应 Store 状态:当检测到水印节点被移除,且
watermarkStore.visible === true,立刻重建 canvas 并重绘 -
动态生成类名与 ID:canvas 元素的
id和 class 使用哈希(如hash(`${user.id}-${Date.now()}`)),不写死#watermark,增加自动化清除难度










