最省事方案是用::before伪元素在body或主容器加固定水印,需设position:fixed、z-index≥9999、transform:rotate(-30deg)和opacity:0.08,并动态注入内容。

用 ::before 伪元素加固定水印最省事
仪表盘页面通常结构稳定、内容区域明确,::before 是最快落地的方案。它不污染 DOM,也不影响 React/Vue 组件的渲染逻辑,适合在 body 或主容器上直接覆盖一层轻量水印。
常见错误是直接写 body::before { content: "©2026" } 却没设 position: fixed 和 z-index,结果水印被内容遮住或随滚动消失。
- 必须加
position: fixed(不是absolute),否则滚动时水印会移出视口 -
z-index至少设为9999,避免被图表库(如 ECharts、Chart.js)的 canvas 层压住 - 用
transform: rotate(-30deg)+opacity: 0.08控制可读性与干扰度,太淡看不清,太浓影响数据阅读 - 文字内容建议动态注入(比如从
data-user-id属性读取),避免硬编码导致多人共用同一水印
Canvas 水印防截图盗用,但要注意 resize 重绘
仪表盘常被截图传播,纯 CSS 水印一删即没;Canvas 方案把水印“画进”视觉层,截图时会一并捕获,适合对版权敏感的场景。
关键坑在于:Canvas 初始尺寸按 window.innerWidth/window.innerHeight 设置后,窗口缩放或切换横竖屏时不会自动更新,水印会拉伸、错位甚至消失。
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 必须监听
resize事件,每次触发都调用canvas.width/canvas.height重设尺寸,并重新fillText - 避免在
requestAnimationFrame里反复绘制——仪表盘本身可能已有高频渲染,叠加 Canvas 绘制容易掉帧 - 水印文本别用固定像素字号(如
24px),改用1.2rem或2vw,适配高分屏和缩放 - 如果仪表盘用了 iframe 嵌入子应用(如报表模块),Canvas 只能作用于当前 window,iframe 内容需单独注入
给 ECharts 图表加水印,别碰 graphic 配置项
ECharts 自带 graphic 支持图层绘制,但它是 SVG 渲染模式下的附加图形,导出 PNG 时默认不包含,且在 Canvas 渲染模式下完全无效——也就是说,你配置了也白配。
真正可靠的方式,是把水印画在 ECharts 容器的父级 DOM 上,用绝对定位盖住整个图表区域。
- 不要依赖
option.graphic,它既不跨渲染引擎,也不保证导出一致性 - 给 ECharts 的
div容器加position: relative,再用一个div.watermark-overlay绝对定位覆盖,设置pointer-events: none - 如果图表支持多主题(light/dark),水印颜色要同步切换,否则深色背景上灰字看不见
- 避免用
z-index: -1把水印塞到图表下面——ECharts 的 tooltip、markLine 等浮层会把它挡住
动态水印内容别写死,用 document.currentScript 读取参数
仪表盘常需绑定用户身份(如工号、部门)、访问时间或会话 ID,这些不能靠后端模板硬塞,得前端运行时注入,否则多个用户看到同一份静态 HTML 就全一样了。
最容易被忽略的是加载时机:如果水印 JS 在 DOMContentLoaded 后才执行,而仪表盘数据已渲染完毕,水印可能盖不住刚插入的卡片或表格。
- 把水印脚本放在
末尾,用document.currentScript获取当前 script 标签的dataset属性传参,例如:<script data-user="U12345" src="watermark.js"></script> - 不要等
window.onload,它等所有图片、字体加载完,延迟太高;改用requestIdleCallback或直接在 script 标签内执行 - 时间戳别用
Date.now()一次生成,应每 30 秒刷新一次 DOM 中的水印文本节点,防止截图后水印时间长期不变 - 若仪表盘支持离线缓存(PWA),水印 JS 必须标记
defer或用type="module",否则 Service Worker 可能缓存旧版本导致用户信息错乱
Canvas 水印看似牢靠,但仪表盘里大量使用第三方可视化库、iframe 和动态 DOM 插入,真正难的从来不是“怎么画”,而是“画在哪、什么时候画、画几次、画完会不会被覆盖”。


















