前端水印实现方案详细举例介绍

 更新时间:2026年06月01日 10:22:25   作者:三翼鸟数字化技术团队  
前端水印技术常用于防止信息泄露或追溯数据来源,尤其在后台管理系统、数据可视化平台中应用广泛,这篇文章主要介绍了前端水印实现方案的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

1. 背景

为了防止信息泄露或知识产权被侵犯,我们可以给数据或图片加一层水印,水印能够很好的保护知识产权。

2. 方式

水印的添加根据环境可以分为两大类,前端浏览器环境添加和后端服务环境添加

  1. 前端实现的特点

    1. 可以不占用服务器资源,完全依赖客户端的计算能力,减少服务端压力
    2. 速度快,无论哪种前端的实现方式,性能都是优于后端的
    3. 实现方式简单
    4. 安全系数较低,对于掌握一定前端知识的人来说可以通过各种骚操作跳过水印获取到源文件
  2. 后端实现的特点

    1. 安全,安全,安全
    2. 当遇到大文件密集水印,或是复杂水印,占用服务器内存、运算量,请求时间过长

3. 前端实现方案

3.1 重复的dom元素覆盖实现

  • 在页面上覆盖一个蒙层,设置蒙层的透明度,设置pointer-events为none, 实现点击穿透
  • 生成一个水印片,上面是显示水印的文字,我们可以给文字加一个旋转,和 userSelect 属。 性,让此时的文字无法被选中
  • 在蒙层上重复循环生成水印片
 divWaterMark (width, height, content) {
      const waterWrapper = document.createElement('div')
      cssHelper(waterWrapper, {
        position: 'fixed',
        top: '0px',
        right: '0px ',
        bottom: '0px',
        left: '0px',
        overflow: 'hidden',
        display: 'flex',
        'flex-wrap': 'wrap',
        'pointer-events': 'none'
      })
      const waterHeight = width
      const waterWidth = height
      const { clientWidth, clientHeight } = document.documentElement || document.body
      const column = Math.ceil(clientWidth / waterWidth)
      const rows = Math.ceil(clientHeight / waterHeight)

      for (let i = 0; i < column * rows; i++) {
        const wrap = document.createElement('div')
        cssHelper(
          wrap,
          Object.create({
            position: 'relative',
            width: `${waterWidth}px`,
            height: `${waterHeight}px`,
            flex: `0 0 ${waterWidth}px`,
            overflow: 'hidden'
          })
        )
        wrap.appendChild(createItem(content))
        waterWrapper.appendChild(wrap)
      }
      document.body.appendChild(waterWrapper)
    },

3.2 canvas 实现方式

创建一个canvas画布,绘制出一个水印区域,将这个水印通过toDataURL方法输出为一个图片,将这个图片设置为蒙层的背景图,通过图片的backgroud-repeat:repeat;样式实现填满整个屏幕的效果

const createWaterMark = (width, height, content) => {
        const angle = -20
        const txt = content
        const canvas = document.createElement('canvas')
        canvas.width = width
        canvas.height = height
        const ctx = canvas.getContext('2d')
        ctx.clearRect(0, 0, width, height)
        ctx.fillStyle = '#000'
        ctx.globalAlpha = 0.1
        ctx.font = `16px serif`
        ctx.rotate((Math.PI / 180) * angle)
        ctx.fillText(txt, 0, 50)
        return canvas.toDataURL()
      }
      const watermakr = document.createElement('div')
      watermakr.className = 'watermark'
      watermakr.style.backgroundImage = `url(${createWaterMark()})`
      document.body.appendChild(watermakr)
      
<style>
.watermark {
  position: fixed;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  pointer-events: none;
  background-repeat: repeat;
}
</style>

3.3 svg实现

svg 和 canvas 类似,只不过是生成背景图的方法换成了通过svg生成

4. 水印破解

上面实现水印的方法,都存在一个问题很明显的问题,那就是对于有些前端知识的人来说通过开发者调试工具稍微操作一下,就能够导致水印失效:

  • 删除对应 dom 节点
  • 设置对应 dom 节点的 css 样式

5. 水印防御

MutationObserver

MutationObserver 是一个可以监听DOM结构变化的接口,能够监听 DOM 树属性、节点本身、子节点 等的变化。防御思路就是就是使用 MutationObserver 去监听外部对应 water-mark 节点的操作,只要监听到了就重新渲染水印效果即可。

主要观察的有三点

  • 水印元素本身是否被移除
  • 水印元素属性是否被篡改(display: none ...)
  • 水印元素的子元素是否被移除和篡改 (element生成的方式 )
createObserver () {
      // 创建一个观察器实例并传入回调函数
      const observer = new MutationObserver(this.callback)
      observer.disconnect()
      // 以上述配置开始观察目标节点
      observer.observe(targetNode, config)
    },
    // 当观察到变动时执行的回调函数
    callback (mutationsList, observer) {
      const watermark = this.watermakr
      const style = this.style
      const currStyle = watermark.getAttribute('style')

      for (let mutation of mutationsList) {
        // 检测元素样式被修改
        if (
          mutation.type === 'attributes' &&
          mutation.target === watermark &&
          currStyle !== style
        ) {
          watermark.setAttribute('style', style)
        }
        // 检测元素被删除
        mutation.removedNodes.forEach(item => {
          console.log(item.type, item.target, currStyle)
          if (item === watermark) {
            // document.body.appendChild(targetNode)
            this.canvasWaterMark(180, 100, '水印加密')
            this.createObserver()
          }
        })
      }
    }

6. 图片加水印

在图片上加水印的实现思路是,图片加载成功后画到canvas中,随后在canvas中绘制水印,完成后通过canvas.toDataUrl()方法获得base64并替换原来的图片路径

addWaterMarkToImg (imgUrl, cb, content) {
      const img = new Image()
      img.src = imgUrl
      img.crossOrigin = 'anonymous'
      img.onload = function () {
        const canvas = document.createElement('canvas')
        canvas.width = img.width
        canvas.height = img.height
        const ctx = canvas.getContext('2d')

        ctx.drawImage(img, 0, 0)
        ctx.textAlign = 'center'
        ctx.textBaseline = 'middle'
        ctx.font = '20px Microsoft Yahei'
        ctx.fillStyle = 'rgba(184, 184, 184, 0.8)'
        const textX = 100
        const textY = 30
        ctx.fillText(content, img.width - textX, img.height - textY)
        const base64Url = canvas.toDataURL()
        cb && cb(base64Url)
      }
      
     // 给图片加水印
    const url = 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/66a8e7cc0a0d4b0ba4130a43c796ad52~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image'
    this.addWaterMarkToImg(url, (base64Url) => {
      document.querySelector('img').src = base64Url
    }, '水印加密')

7. 暗水印

暗水印是一种肉眼不可见的水印方式,可以保持图片美观的同时,保护资源版权

原理 :暗水印的生成方式有很多,常见的为通过修改RGB分量值的小量变动、DWT、DCT 和 FFT 等等方法。每个像素点都是由 RGB 三种元素构成。当我们把其中的一个分量修改,人的肉眼是很难看出其中的变化。

简单的说,对图片像素的处理,加密的信息散布在每个像素点上。

到此这篇关于前端水印实现方案的文章就介绍到这了,更多相关前端水印实现方案内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • ECMAScript 创建自己的js类库

    ECMAScript 创建自己的js类库

    ECMAScript中最有意思,最强大的地方在于函数。最进在完善自己的js类库的时候发现我们经常在用函数,但真的很少有人懂得ECMAScript函数功能
    2012-11-11
  • JS生成不重复的随机数组的简单实例

    JS生成不重复的随机数组的简单实例

    下面小编就为大家带来一篇JS生成不重复的随机数组的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • 微信小程序实现动态渲染Markdown示例详解

    微信小程序实现动态渲染Markdown示例详解

    这篇文章主要为大家介绍了微信小程序实现动态渲染Markdown示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • 用POSTMAN发送JSON格式的POST请求示例

    用POSTMAN发送JSON格式的POST请求示例

    这篇文章主要介绍了用POSTMAN发送JSON格式的POST请求示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • JavaScript实现ASC转汉字及汉字转ASC的方法

    JavaScript实现ASC转汉字及汉字转ASC的方法

    这篇文章主要介绍了JavaScript实现ASC转汉字及汉字转ASC的方法,涉及JavaScript编码转换的相关技巧,需要的朋友可以参考下
    2016-01-01
  • 判断横屏竖屏(三种)

    判断横屏竖屏(三种)

    本文主要介绍了通过HTML,CSS,JS三种判断横屏竖屏的方法。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • Js利用console计算代码运行时间的方法示例

    Js利用console计算代码运行时间的方法示例

    最近看了一本书,发现了个计算代码执行时间的方法,感觉还挺有用的,所以这篇文章主要给大家介绍了关于Javascript利用console计算代码运行时间的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
    2017-09-09
  • bootstrap3-dialog-master模态框使用详解

    bootstrap3-dialog-master模态框使用详解

    这篇文章主要为大家详细介绍了bootstrap3-dialog-master模态框的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • js实现聊天对话框

    js实现聊天对话框

    这篇文章主要为大家详细介绍了js实现聊天对话框,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • 微信小程序开发实用技巧之数据传递和存储

    微信小程序开发实用技巧之数据传递和存储

    数据传递与存储是我们在日常开发中遇到的再正常不过的一个需求, 这篇文章主要给大家介绍了关于微信小程序开发实用技巧之数据传递和存储的相关资料,需要的朋友可以参考下
    2021-05-05

最新评论