导读:本期聚焦于守望者创作的《js怎样实现水印添加功能?页面水印添加的3种技术方案详解》,敬请观看详情。页面被截图外传后查不到来源?给网页加上用户专属水印就能解决这个溯源难题。本文整理了前端实现水印的几种主流思路:用canvas直接绘制文字或图片水印并平铺到页面、基于SVG背景图生成更清晰可控的水印样式、通过重复的DOM元素配合MutationObserver防御水印被手动删除。文中对比了各方案的兼容性、清晰度、防篡改能力与性能开销,并给出可直接运行的完整代码,还介绍了透明度设置、旋转角度、平铺密度等常见调参技巧,以及全屏水印与局部水印的适用场景,帮助你根据业务需求快速选定合适的实现方式。

水印功能在企业后台系统里越来越常见,主要用途是防泄密溯源:页面上叠加显示当前登录用户的姓名和工号,一旦有人截图外传,就能通过水印快速定位到泄露源头。用原生js实现页面水印并不复杂,核心思路就是把带有用户信息的文字或图案,以半透明、平铺的方式覆盖在整个页面上,同时阻止用户通过开发者工具随意删除。下面详细介绍三种主流实现方案。

js怎样实现水印添加功能?页面水印添加的3种技术方案详解

方案一:canvas绘制水印并平铺为背景

这是最经典的实现方式。原理是先用canvas画出一个小的水印单元,包含文字内容、旋转角度和透明度,然后调用toDataURL把它转成base64图片,最后设置成某个覆盖层的背景图并开启repeat平铺。这种方式的优点是兼容性极好,几乎所有支持canvas的浏览器都能运行,而且生成的是位图,渲染性能稳定。

具体实现时需要注意几个细节:水印单元的宽高要根据文字长度计算,避免相邻水印互相重叠;旋转角度一般取-20度到-30度,视觉上更像传统水印;透明度建议控制在0.05到0.15之间,太淡起不到警示作用,太浓会干扰正常阅读。下面是完整的工具函数:

function generateWatermark(options) {
  var opts = options || {};
  var text = opts.text || '水印文字';
  var fontSize = opts.fontSize || 16;
  var rotate = opts.rotate || -22;
  var opacity = opts.opacity || 0.1;

  // 创建canvas并计算水印单元尺寸
  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('2d');
  ctx.font = fontSize + 'px Arial';
  var textWidth = ctx.measureText(text).width;
  canvas.width = textWidth + 80;
  canvas.height = fontSize + 60;

  // 重新设置字体(canvas重设宽高后状态会丢失)
  ctx.font = fontSize + 'px Arial';
  ctx.fillStyle = 'rgba(0, 0, 0, ' + opacity + ')';
  ctx.translate(canvas.width / 2, canvas.height / 2);
  ctx.rotate(rotate * Math.PI / 180);
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.fillText(text, 0, 0);

  // 转成base64并应用到覆盖层
  var dataUrl = canvas.toDataURL('image/png');
  var layer = document.createElement('div');
  layer.id = 'watermark-layer';
  layer.style.cssText =
    'position:fixed;top:0;left:0;width:100%;height:100%;' +
    'pointer-events:none;z-index:99999;' +
    'background-image:url(' + dataUrl + ');' +
    'background-repeat:repeat;';
  document.body.appendChild(layer);
  return layer;
}

// 调用示例
generateWatermark({ text: '张三 10086', fontSize: 16 });

代码里的pointer-events:none非常关键,它保证水印层不会拦截鼠标事件,用户在页面上点击、滚动都不受影响。另外z-index要设置得足够大,确保水印始终显示在其他元素之上,否则被弹窗盖住就失去意义了。

方案二:SVG背景图生成高清水印

canvas生成的是位图,在高分屏上可能出现模糊。SVG是矢量格式,无论怎么缩放都保持清晰,而且SVG可以直接内联文本,生成的base64字符串比同尺寸的PNG更小。它的实现思路和方案一类似,只是把绘制环节换成了拼装SVG字符串,再通过encodeURIComponent编码后塞进url()里。

SVG方案还有一个隐藏优势:文字内容是动态拼接的,不需要等canvas异步绘制,逻辑上是同步的,代码更直观。缺点是低版本浏览器(比如IE11以下)对SVG背景的支持不完善,如果项目需要兼容老浏览器就要谨慎选择。示例如下:

function createSvgWatermark(text) {
  var svgText =
    '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="120">' +
    '<text x="50%" y="50%" ' +
    'font-size="16" fill="rgba(0,0,0,0.12)" ' +
    'text-anchor="middle" ' +
    'transform="rotate(-22, 100, 60)">' + text + '</text>' +
    '</svg>';

  var bgUrl = 'url("data:image/svg+xml,' +
    encodeURIComponent(svgText) + '")';

  var div = document.createElement('div');
  div.style.cssText =
    'position:fixed;inset:0;pointer-events:none;z-index:99999;' +
    'background-image:' + bgUrl + ';background-repeat:repeat;';
  document.body.appendChild(div);
  return div;
}

createSvgWatermark('李四 9527');

拼接SVG字符串时标签里的尖括号必须转义处理,尤其是通过encodeURIComponent编码的场景,双引号和井号等特殊字符也要一并编码,否则背景图会解析失败导致水印不显示。建议在retina屏幕较多的移动端项目中优先考虑这种方案。

方案三:DOM重复元素加MutationObserver防篡改

前两种方案都是背景图平铺,有个共同的软肋:用户打开控制台,选中水印层按Delete键就能删掉。如果业务对防篡改有要求,就需要引入MutationObserver监听DOM变化,一旦发现水印被删除或样式被修改,立即重建水印。这种方式也常和方案一、二组合使用,即背景图负责展示,观察器负责防御。

MutationObserver是浏览器原生的DOM变化监听API,性能开销比旧式的MutationEvent小得多。它的用法是创建观察器实例,指定回调函数,然后调用observe注册要监听的目标节点和事件类型。当目标节点的子节点被增删、属性被修改时,回调就会被触发:

var watermarkLayer = generateWatermark({ text: '王五 12345' });

var observer = new MutationObserver(function () {
  // 水印被删或被改时先停止监听,避免无限循环
  observer.disconnect();
  var existing = document.getElementById('watermark-layer');
  if (existing) {
    existing.parentNode.removeChild(existing);
  }
  // 重新生成水印并恢复监听
  watermarkLayer = generateWatermark({ text: '王五 12345' });
  observe();
});

function observe() {
  observer.observe(document.body, {
    childList: true,        // 监听子节点增删
    subtree: true,          // 监听整个子树
    attributes: true,       // 监听属性修改
    attributeFilter: ['style', 'class']
  });
}

observe();

回调里先调用disconnect再重建水印,这一步容易被忽略。如果不这样做,重建水印本身也会触发observer,造成无限递归,页面会直接卡死。另外要注意,前端防御终究是君子协定,用户禁用js或者直接截图后裁掉水印,前端无能为力,真正的强防护需要服务端配合,比如在返回的图片资源上做盲水印。

三种方案对比与选型建议

三个方案各有侧重,可以简单对比一下:canvas方案兼容性最好、生态成熟,适合大多数后台系统;SVG方案清晰度高、体积小,适合高分屏和移动端;MutationObserver方案本身不负责绘制,主要价值在于防篡改,通常与前两者搭配。实际项目中建议canvas或SVG负责渲染,再用observer做一层保护,这是目前开源水印库(比如watermark-js、@watermark-plus等)普遍采用的架构。

还有几个工程化细节值得注意。第一,水印内容不要只写姓名,最好拼上工号和时间戳,溯源信息才完整。第二,如果页面存在多个路由切换,要确保水印层挂在body下而不是组件内部,否则路由跳转时水印会跟着销毁。第三,对于表格、详情页等局部区域加水印的场景,可以把覆盖层的position:fixed改成absolute并限定在容器内,实现原理完全一致。

最后提醒一点,水印只是防泄密的辅助手段,它能提高泄露的溯源效率,但不能从根源上阻止泄露。涉及高敏感数据的系统,还应该配合权限控制、操作日志、页面禁右键、动态水印轮换等措施,形成完整的防护链路。

js水印canvas水印页面水印修改时间:2026-09-05 06:24:38

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260905/50728.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。