【前端实战】网页水印实现方案(防删除+自适应+高兼容性)

在前端开发中,网页水印是一个非常常见的需求,主要用于环境标识(如测试环境、生产环境)版权保护数据安全等场景。一个合格的网页水印需要满足防删除、自适应窗口、高兼容性等特性,本文将基于 Canvas + DOM 监听的方式,实现一个健壮的网页水印工具,并结合 Vue 项目演示实际使用流程。

一、核心实现思路

网页水印的核心实现逻辑分为以下几步:

  1. Canvas 生成水印图片:利用 Canvas 绘制水印文字(支持旋转、透明度、字体样式),并转换为 Base64 格式的图片。
  2. DOM 挂载水印容器:创建一个全屏的 div 容器,将 Canvas 生成的图片作为背景图,挂载到页面根节点(document.documentElement),确保水印覆盖整个页面。
  3. 防删除机制:通过定时检测水印元素是否存在,若被删除则重新生成;同时使用随机 ID + 自定义属性双重标记水印元素,提升防删除能力。
  4. 自适应处理:监听窗口大小变化,当窗口缩放时重新生成水印,保证水印布局不会错位。
  5. 兼容性处理:添加 try-catch 捕获异常(如 Canvas 的 toDataURL 方法被 CSP 限制),兼容不同浏览器和页面环境。

二、完整代码实现(水印工具类)

我们将水印功能封装为一个独立的工具类 watermark.js,便于在项目中复用:

/** * 网页水印工具类 * 功能:生成防删除、自适应、高兼容性的网页水印 * 作者:前端无涯https://blog.ZEEKLOG.net/weixin_44439817?type=blog * 日期:2025-12-15 */let watermark ={}/** * 生成水印元素并挂载到页面 * @param {string} str - 水印显示的文字内容 * @returns {string|null} - 水印元素的ID(失败返回null) */letsetWatermark=(str)=>{// 生成随机ID,防止被反调试脚本通过固定ID清除let id ='wm-'+ Math.random().toString(36).substr(2,9)try{// 1. 创建Canvas元素,绘制水印文字let can = document.createElement('canvas')// 设置Canvas尺寸(水印的单个重复单元大小) can.width =200 can.height =150let cans = can.getContext('2d')// 文字旋转(-20度,斜向显示) cans.rotate(-20* Math.PI/180)// 文字样式:字体、透明度、颜色 cans.font ='20px Verdana' cans.fillStyle ='rgba(100, 100, 100, 0.2)'// 文字对齐方式 cans.textAlign ='left' cans.textBaseline ='middle'// 绘制文字(位置:Canvas宽/8,高/2) cans.fillText(str, can.width /8, can.height /2)// 2. 创建水印容器divlet div = document.createElement('div') div.id = id // 添加自定义属性,用于双重检测水印元素 div.setAttribute('data-watermark','true')// 3. 设置水印容器样式(全屏覆盖、层级最高、不可点击) div.style.pointerEvents ='none'// 防止水印遮挡页面元素的点击事件 div.style.top ='0px' div.style.left ='0px' div.style.position ='fixed'// 固定定位,跟随窗口滚动 div.style.zIndex ='2147483647'// 最高层级,确保覆盖所有元素 div.style.width ='100vw'// 视口宽度 div.style.height ='100vh'// 视口高度 div.style.display ='block !important'// 强制显示 div.style.visibility ='visible !important'// 强制可见// 4. 将Canvas图片设置为背景图(兼容CSP限制,添加try-catch)try{ div.style.background ='url('+ can.toDataURL('image/png')+') left top repeat'}catch(e){ console.error('Watermark canvas toDataURL error:', e)}// 5. 挂载到documentElement(比body更稳定,避免body被样式限制) document.documentElement.appendChild(div) console.log('Watermark element appended:', id)return id }catch(err){ console.error('Watermark creation failed:', err)returnnull}}/** * 初始化水印(对外暴露的方法,仅允许有效调用一次) * @param {string} str - 水印文字内容 */ watermark.set=(str)=>{// 延迟执行(1秒),确保DOM完全加载后再生成水印setTimeout(()=>{let currentId =setWatermark(str)// 定时检测(每2秒),防止水印被删除或隐藏setInterval(()=>{// 检测方式1:通过ID判断水印元素是否存在if(currentId && document.getElementById(currentId)===null){ console.warn('Watermark removed, recreating...') currentId =setWatermark(str)}// 检测方式2:通过自定义属性双重验证(防止ID被篡改)const wm = document.querySelector('div[data-watermark="true"]')if(!wm){ currentId =setWatermark(str)}},2000)// 窗口大小变化时,重新生成水印(自适应) window.onresize=()=>{// 仅当水印不存在时重建,避免频繁操作导致闪烁if(currentId && document.getElementById(currentId)===null){setWatermark(str)}}},1000)// 延迟1秒,确保页面DOM渲染完成}exportdefault watermark 

三、Vue 项目中使用水印工具

以 Vue 2/3 项目为例,我们在根组件 App.vue 中引入并使用水印工具,实现全局水印效果:

<template> <div> <!-- 路由视图 --> <router-view /> </div> </template> <script> // 引入水印工具类 import watermark from "@/utils/watermark" export default { name: "App", components: { ThemePicker }, // 挂载完成后初始化水印 mounted() { // 设置水印内容:这里为“测试环境”,可根据环境动态传入(如生产环境、开发环境) watermark.set("测试环境-前端无涯") } } </script> <style scoped> /* 示例样式:隐藏主题选择器,可根据项目情况删除 */ #app .theme-picker { display: none; } </style> 

四、关键优化点解析

本文的水印方案相比传统实现,做了以下关键优化,提升了健壮性和兼容性:

1. 防删除机制升级
  • 随机 ID:水印元素的 ID 使用 wm- + 随机字符串生成,避免被攻击者通过固定 ID 直接删除。
  • 双重检测:定时检测时,既通过 ID 检查,又通过自定义属性 data-watermark="true" 检查,即使 ID 被篡改,也能检测到水印被删除。
  • 定时重建:每 2 秒检测一次,若水印被删除则立即重新生成,让攻击者的删除操作失效。
2. 兼容性提升
  • 挂载到 document.documentElement:相比挂载到 bodydocumentElement(html 标签)更稳定,不会因 body 的样式(如 overflow: hiddenposition: relative)导致水印显示异常。
  • try-catch 捕获异常:包裹 Canvas 的 toDataURL 方法,防止因页面 CSP(内容安全策略)限制导致水印生成失败。
  • 延迟执行:初始化水印时延迟 1 秒执行,确保页面 DOM 完全加载后再生成水印,避免因 DOM 未加载完成导致挂载失败。
3. 用户体验优化
  • pointer-events: none:水印容器设置该样式,不会遮挡页面元素的点击、hover 等交互事件,不影响用户操作。
  • 固定定位 + 视口尺寸:使用 position: fixed + 100vw/100vh,确保水印覆盖整个视口,且跟随窗口滚动。
  • resize 自适应:监听窗口大小变化,仅在水印不存在时重建,避免频繁操作导致水印闪烁。
4. 样式强制生效

水印容器设置 display: block !importantvisibility: visible !important,防止被攻击者通过样式隐藏水印。

五、常见问题与解决方案

在实际使用中,可能会遇到以下问题,可参考对应解决方案:

1. 水印不显示
  • 检查 Canvas 绘制是否正常:可在控制台打印 can.toDataURL('image/png'),查看是否生成有效的 Base64 字符串。
  • 检查水印容器的 z-index:确保 z-index 足够高(本文使用 2147483647,是浏览器允许的最大安全值),未被其他元素覆盖。
  • 检查页面 CSP 策略:若控制台报错 toDataURL is not allowed,需在服务端配置 CSP 策略,允许 data: 协议。
2. 水印被遮挡
  • 检查水印容器的 position:确保为 fixed,而非 absolute(absolute 会受父元素定位影响)。
  • 检查页面元素的 z-index:若某些元素的 z-index 超过 2147483647,可适当提高水印的 z-index(但不建议超过浏览器最大值),或调整页面元素的 z-index。
3. 窗口缩放后水印错位

本文的方案已监听 window.onresize 事件,在窗口缩放时重新生成水印,若仍出现错位,可将 resize 事件的处理逻辑改为立即重建水印(而非仅在不存在时重建):

window.onresize=()=>{ currentId =setWatermark(str)// 直接重建}

六、扩展功能(可选)

根据实际需求,可对水印工具进行扩展:

  1. 自定义水印样式:将字体、颜色、透明度、旋转角度等参数作为配置项传入,支持自定义水印样式。
  2. 多行水印文字:修改 Canvas 绘制逻辑,支持多行文字水印。
  3. 动态修改水印内容:添加 watermark.update(str) 方法,支持运行时动态修改水印文字。
  4. 图片水印:在 Canvas 中绘制图片,实现图片 + 文字组合水印。

七、总结

本文实现的网页水印方案,通过 Canvas 生成水印图片,结合 DOM 监听和定时检测机制,实现了防删除、自适应、高兼容性的核心需求。该方案已在 Vue 项目中验证,可直接复用至 React、Angular 等前端框架,也可用于纯 HTML/JS 项目。

在实际项目中,可根据环境(如开发、测试、生产)动态传入水印内容,进一步提升水印的实用性。同时,建议结合后端接口,获取用户信息(如用户名、工号)作为水印内容,实现更精细化的版权保护。

Read more

RUST异步微服务架构的最佳实践与常见反模式

RUST异步微服务架构的最佳实践与常见反模式

RUST异步微服务架构的最佳实践与常见反模式 一、项目优化前的问题分析 1.1 任务调度不合理 💡在第21篇项目中,用户同步服务的任务调度使用了Cron调度器,但Cron调度器的精度有限,可能导致任务执行延迟。此外,任务的并发度没有配置,可能导致任务积压。 1.2 I/O资源限制不足 订单处理服务的TCP连接队列大小没有配置,可能导致连接失败。数据库连接池的大小没有配置,可能导致数据库连接耗尽。 1.3 同步原语使用不当 实时监控服务中,Redis连接没有使用连接池,可能导致连接开销过大。任务结果的处理没有使用批量操作,可能导致上下文切换过多。 1.4 错误处理不完善 任务失败的处理逻辑不够完善,没有进行任务重试和错误统计。服务之间的通信没有进行超时管理和错误处理。 二、异步架构设计模式的应用 2.1 命令查询分离(CQS) CQS是一种架构设计模式,将系统的操作分为命令和查询两种类型。命令用于修改系统状态,查询用于获取系统状态,两者互不干扰。 在项目中,我们可以将用户同步任务视为命令操作,将系统状态查询视为查询操作: // 用户同步任务(

By Ne0inhk
新能源汽车电子架构革命:深度解析AUTOSAR标准与实践

新能源汽车电子架构革命:深度解析AUTOSAR标准与实践

新能源汽车电子架构革命:深度解析AUTOSAR标准与实践(附完整技术图谱) 引言:软件定义汽车时代的破局之道 在特斯拉FSD芯片算力突破72TOPS、华为ADS 2.0实现城市高阶智驾的今天,一场围绕汽车"大脑"的战争正在悄然打响。传统分布式电子架构已逼近物理极限,而集中式EE架构的进化离不开底层软件的革新——这就是AUTOSAR标准诞生的时代背景。本文将从技术原理、工程实践、未来趋势三个维度,为您揭开智能汽车灵魂的神秘面纱。 目录 * 第一章 AUTOSAR的前世今生:汽车软件革命的序章 * 第二章 技术解密:AUTOSAR的三层架构精要 * 第三章 工程实践:AUTOSAR落地全流程详解 * 第四章 进阶应用:新能源汽车场景实践 * 第五章 未来趋势:AUTOSAR的进化之路 * 结语:站在软件定义汽车的十字路口 第一章 AUTOSAR的前世今生:汽车软件革命的序章 1.1 行业困局:当摩尔定律遇见机械工业 (插入图表:2010-2025年汽车ECU数量增长曲线) 传统架构痛点解析: 硬件依赖症:

By Ne0inhk
【MYSQL】MYSQL学习的一大重点:MYSQL库的操作

【MYSQL】MYSQL学习的一大重点:MYSQL库的操作

🎬 个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬 艾莉丝的简介: 文章目录 * 0 ~> 实际场景:创建和删除数据库 * 0.1 创建方式1 * 0.2 创建方式2 * 0.3 创建方式3 * 1 ~> 数据库的编码集 * 1.1 目前整个数据库支持的字符集 * 1.2 目前整个数据库支持的字符集 * 1.3 UTF-8需要设置配置文件 * 1.4 MySQL 中与字符集排序规则(

By Ne0inhk
IoTDB AINode 实战指南:SQL 原生时序 AI 建模,毫秒级预测 / 异常检测落地

IoTDB AINode 实战指南:SQL 原生时序 AI 建模,毫秒级预测 / 异常检测落地

IoTDB AINode 实战指南:SQL 原生时序 AI 建模,毫秒级预测 / 异常检测落地 AINode 作为 IoTDB 原生时序 AI 节点,内置 Timer 系列等业界领先时序大模型,支持通过标准 SQL 语句完成模型注册、管理与推理全流程,无需 Python/Java 编程,更无需迁移 IoTDB 存储的数据。本文详细拆解 AINode 的核心优势、模型注册 / 调用 / 权限管理等关键操作,结合电力负载预测、变电站电压预测、民航旅客异常检测三大工业级案例,手把手演示如何通过简单 SQL 实现时序数据的趋势预测、缺失值填补与异常识别,助力开发者快速落地毫秒级实时时序 AI 应用。 AINode 是支持时序相关模型注册、管理、调用的 IoTDB

By Ne0inhk