因为CSS background-image在截图等场景下易丢失,真防盗需用Canvas动态绘制全屏水印并覆盖页面,结合多端兼容处理与动态内容绑定。

uni-app 页面水印为什么不能用 CSS background-image 简单实现
因为 background-image 在截图、长按保存图片、WebView 截图等场景下极易丢失——尤其在 iOS 的 web-view 或小程序 canvas 渲染层中,背景图不参与实际 DOM 绘制,也不被原生截图 API 捕获。真防盗图必须让水印成为「可绘制的、叠加在内容之上的真实节点」或「Canvas 贴图层」。
用 Canvas 动态绘制全屏水印并覆盖页面(推荐方案)
核心思路:创建一个 canvas 元素,用 JS 计算屏幕尺寸与设备像素比(uni.getSystemInfoSync().pixelRatio),动态绘制倾斜、半透明、带用户信息的文本水印,并通过 position: fixed 全屏覆盖。关键点是 canvas 必须用 width/height 属性设置物理像素尺寸,而非 CSS 宽高。
- 在
中插入:<canvas canvas-id="watermarkCanvas" class="watermark-canvas"></canvas>
- 在
onReady中执行绘制:const query = uni.createSelectorQuery().in(this);<br>query.select('#watermarkCanvas').fields({ node: true, size: true }).exec((res) => {<br> const canvas = res[0].node;<br> const ctx = canvas.getContext('2d');<br> const dpr = uni.getSystemInfoSync().pixelRatio;<br> const width = res[0].width * dpr;<br> const height = res[0].height * dpr;<br> canvas.width = width;<br> canvas.height = height;<br> ctx.scale(dpr, dpr);<br> ctx.rotate((-20 * Math.PI) / 180);<br> ctx.font = 'normal bold 16px sans-serif';<br> ctx.fillStyle = 'rgba(0, 0, 0, 0.08)';<br> ctx.textAlign = 'left';<br> ctx.fillText('USER_ID:123456', -20, 30);<br>}); - 对应 CSS 必须设为全屏固定定位:
.watermark-canvas {<br> position: fixed;<br> top: 0;<br> left: 0;<br> width: 100vw;<br> height: 100vh;<br> pointer-events: none;<br> z-index: 9999;<br>}
uni-app 条件编译下各端水印兼容性差异
不同平台对 canvas 渲染支持不一:微信小程序支持 canvas 2D 上下文但不支持 toDataURL 导出;H5 端需注意 transform: scale() 缩放后 canvas 像素错位;App 端(iOS WKWebview)可能拦截 canvas 绘制导致白屏。务必加兜底逻辑。
- H5 端优先用
canvas+pointer-events: none,避免遮挡点击 - 微信小程序需改用
uni.createCanvasContext('watermarkCanvas', this),且绘制后必须调用draw(true) - App 端若 canvas 失效,降级为绝对定位的 SVG 水印(用
内联 base64 文本路径),但 SVG 不支持透明度动画,需静态生成 - 所有端都应在
onShow重绘一次,防止横竖屏切换后水印错位
水印文字动态绑定与防篡改处理
直接写死文本如 '公司机密' 毫无意义——攻击者可直接改 HTML 或注入 JS。真正有效的做法是把水印内容和当前登录用户强绑定,并加入时间戳或 session ID 哈希片段。
- 从
uni.getStorageSync('userInfo')或 pinia/vuex store 中取userId+loginTime - 用简单哈希(如
md5(userId + '_' + Date.now().toString().slice(-6)))生成短标识,避免暴露原始字段 - 每 30 秒用
setInterval重绘 canvas(仅 H5/App),让截图中的水印时间戳持续变化,增加批量盗图成本 - 禁用右键和长按:在根容器加
@contextmenu.prevent和@touchstart.stop,但注意这会影响部分正常交互,建议只对敏感页启用
水印不是加一层样式就完事,Canvas 的像素控制、多端渲染上下文差异、动态内容绑定时机——这三个地方任一疏漏,防盗效果就归零。特别是 iOS App 端的 WKWebview 对 canvas 的静默失败,很容易被忽略。











