MutationObserver在页面水印实现起到的作用详解

目录
  • 背景
  • 实现水印
  • 恶意修改
  • MutationObserver

背景

大家平时在开发中或者在面试中,难免都会遇到一个问题——给页面加水印,其实这并不难,但是也是有一些注意点的,所以说看似简单的功能,要尽力做到:

  • 1、严谨性
  • 2、安全性

实现水印

其实实现水印并不难,只需要利用自定义指令 + canvas + background-image即可,实现起来也非常方便:

import type { Directive, App } from 'vue'
interface Value {
  font?: string
  textColor?: string
  text?: string
}
const waterMarkId = 'waterMark'
const canvasId = 'can'
const drawWatermark = (el, value: Value) => {
  const {
    font = '16px Microsoft JhengHei',
    textColor = 'rgba(180, 180, 180, 0.3)',
    text = '三心大菜鸟',
  } = value
  // 创建一个canvas标签
  const canvas = document.getElementById(canvasId) as HTMLCanvasElement
  // 如果已有则不再创建
  const can = canvas || document.createElement('canvas')
  can.id = canvasId
  el.appendChild(can)
  // 设置宽高
  can.width = 400
  can.height = 200
  // 不可见
  can.style.display = 'none'
  const ctx = can.getContext('2d')!
  // 设置画布的样式
  ctx.rotate((-20 * Math.PI) / 180)
  ctx.font = font
  ctx.fillStyle = textColor
  ctx.textAlign = 'left'
  ctx.textBaseline = 'middle'
  ctx.fillText(text, can.width / 3, can.height / 2)
  // 水印容器
  const waterMaskDiv = document.createElement('div')
  waterMaskDiv.id = waterMarkId
  // 设置容器的属性样式
  // 将刚刚生成的canvas内容转成图片,并赋值给容器的 background-image 样式
  const styleStr = `
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: -1;
    top: 0;
    left: 0;
    pointer-events: none;
    background-image: url(${can.toDataURL('image/png')})
  `
  waterMaskDiv.setAttribute('style', styleStr)
  // 将水印容器放到目标元素下
  el.appendChild(waterMaskDiv)
  return styleStr
}
const watermarkDirective: Directive = {
  mounted(el, { value }) {
    // 接收styleStr,后面可以用来对比
    el.waterMarkStylestr = drawWatermark(el, value)
  }
}

使用的时候直接以v-watermark来使用:

<div
    v-watermark="
    {
    text: '水印名称',
    textColor: 'rgba(180, 180, 180, 0.3)'
    }
    "
  >

得到的效果如下:

恶意修改

咱们完成了水印功能,但是咱们来想一想,水印有啥用?或者说我们为什么要给一个页面加水印呢?答案就是:防伪

是的,我们的水印是用来防伪的,但是像我们刚刚那么做真的能防伪吗?我们回忆一下我们刚刚的加水印思路:

  • 第一步:创建个canvas且画好水印
  • 第二步:创建个水印容器div标签
  • 第三步:将canvas画布转图片链接,赋值给div标签的background-image样式属性
  • 第四步:将水印容器div放到目标元素之下

看似完成了水印功能,但是其实破绽百出!!!比如:

  • 1、审查元素修改容器div的background-image属性为空

  • 2、审查元素把容器div给删掉

如果一切别有用心的人做了这两件事,这都会导致我们页面上刚刚所做的水印直接消失!!!

所以咱们得监控这些人的恶意行为,那咋做呢?MutationObserver出场了!!!

MutationObserver

MutationObserver的具体用法大家可以去MDN上看,这里我就简言意骇地说一下他的作用:监控DOM元素的变化

是的,它的作用就是:监控DOM元素的变化,所以他能阻止那些恶意用户破坏水印,因为我们刚刚说了,恶意用户可以使用以下两种方法进行破坏水印:

  • 1、审查元素修改容器div的background-image属性为空
  • 2、审查元素把容器div给删掉

而这两点都涉及到DOM的修改,所以都会引起MutationObserver的监控触发,所以咱们可以利用MutationObserevr来监控。这里用到它的实例的两个方法:

  • observe:开启监控DOM变化
  • disconnect:停止监控DOM变化
const watermarkDirective: Directive = {
  mounted(el, { value }) {
    // 接收styleStr,后面可以用来对比
    el.waterMarkStylestr = drawWatermark(el, value)
    // 先定义一个MutationObserver
    el.observer = new MutationObserver(() => {
      const instance = document.getElementById(waterMarkId)
      const style = instance?.getAttribute('style')
      const { waterMarkStylestr } = el
      // 修改样式 || 删除div
      if ((instance && style !== waterMarkStylestr) || !instance) {
        if (instance) {
          // div还在,说明只是修改style
          instance.setAttribute('style', waterMarkStylestr)
        } else {
          // div不在,说明删除了div
          drawWatermark(el, value)
        }
      }
    })
    // 启动监控
    el.observer.observe(document.body, {
      childList: true,
      attributes: true,
      subtree: true,
    })
  },
  unmounted(el) {
    // 指定元素销毁时,记得停止监控
    el.observer.disconnect()
    el.observer = null
  },
}

现在,你修改style或者删除容器div,都会重新生成水印,这样恶意用户就无法得逞啦!!!当然可能还有漏洞,大家可以给给建议!!

以上就是MutationObserver在页面水印实现起到的作用详解的详细内容,更多关于MutationObserver页面水印的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vue实现页面添加水印功能

    创建watermark.js文件 let watermark = {} let setWatermark = (str) => { let id = '1.23452384164.123412416'; if (document.getElementById(id) !== null) { document.body.removeChild(document.getElementById(id)); } //创建一个画布 let can = document.createElement('can

  • vue实现页面添加水印效果

    最近在做项目的时候要求给页面加上水印效果,废话不多说直接上代码: export function watermark(settings) { debugger; //默认设置 var defaultSettings={ watermark_txt:"text", watermark_x:20,//水印起始位置x轴坐标 watermark_y:20,//水印起始位置Y轴坐标 watermark_rows:5,//水印行数 watermark_cols:10,//水印列数 watermar

  • react实现页面水印效果的全过程

    目录 前言 1.使用示例 2.实现过程 3.组件代码 总结 前言 1.为什么选用svg 而不是cavans? 因为cavans 在高分辨率屏幕下,需要根据 devicePixelRatio做宽高的适配,不然就会很模糊,而svg是矢量图,原生支持各种分辨率,不会产生模糊的情况. 1.使用示例 import React from 'react' import ReactDOM from 'react-dom' import './index.css' import WaterMarkContent

  • Vue使用自定义指令实现页面底部加水印

    项目场景 给项目的整个背景加上自定义水印,可以改变水印的文案和字体颜色等 实现思路 这里使用的技术主要是canvas,在实现水印的过程中,主要使用了canvas的特性 使用 canvas 特性生成 base64 格式的图片文件,然后设置其字体大小,颜色等 最后将其设置为背景图片,这就实现了页面的水印效果 实现效果 实现代码 <template> <div class="water-marker" > <div v-waterMarker="{te

  • JavaScript中MutationObServer监听DOM元素详情

    一.基本使用 可以通过MutationObserver构造函数实例化,参数是一个回调函数. let observer = new MutationObserver(() => console.log("change")); console.log(observer); observer对象原型链如下: MutationObserver实例: 可以看到有disconnect.observer.takeRecords方法. 1. observer方法监听 observer方法用于关联

  • MutationObserver在页面水印实现起到的作用详解

    目录 背景 实现水印 恶意修改 MutationObserver 背景 大家平时在开发中或者在面试中,难免都会遇到一个问题——给页面加水印,其实这并不难,但是也是有一些注意点的,所以说看似简单的功能,要尽力做到: 1.严谨性 2.安全性 实现水印 其实实现水印并不难,只需要利用自定义指令 + canvas + background-image即可,实现起来也非常方便: import type { Directive, App } from 'vue' interface Value { font

  • PHP中加速、缓存扩展的区别和作用详解(eAccelerator、memcached、xcache、APC )

    PHP中有eAccelerator.memcached.xcache.APC 4个加速.缓存扩展,下面给大家介绍下其区别,一起看看吧! 折腾VPS的朋友,在安装好LNMP等Web运行环境后都会选择一些缓存扩展安装以提高PHP运行速度,常被人介绍的有 eAccelerator.memcached.xcache.Alternative PHP Cache这几个缓存扩展,它们之间有什么区别?分别的作用又是什么?我们如何选择?这是本文给于大家的答案. 1.eAccelerator eAccelerato

  • JS中的防抖与节流及作用详解

    概念 函数防抖(debounce)是指在一定时间内,在动作被连续频繁触发的情况下,动作只会被执行一次,也就是说当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间,所以短时间内的连续动作永远只会触发一次,比如说用手指一直按住一个弹簧,它将不会弹起直到你松手为止. 函数节流是指一定时间内执行的操作只执行一次,也就是说即预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期,一个比较形象的例子是如果将水龙头拧紧直到水是以水滴的形式流出

  • package.json中homepage属性的作用详解

    Package.json 属性说明 name - 包名. version - 包的版本号. description - 包的描述. homepage - 包的官网 url . author - 包的作者姓名. contributors - 包的其他贡献者姓名. dependencies - 依赖包列表.如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下. repository - 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上.

  • 探索浏览器页面关闭window.close()的使用详解

    说起来window.close(),这也是个"不太让人省心"的角色.因为浏览器兼容性千差万别,还对他有诸多限制. 使用语法: window.close() 场景复现 昨天发现有人在csdn上传违禁文件,举报后来到了这个页面: 里面那个按钮发现点击无效! 就...当时就挺尴尬的. 不过既然它说是[关闭],当时就想到了这个堪称"漏洞百出"的close事件,F12打开控制台一看:果不其然 看到这顿时就来了兴趣 探索过程和解决方案 为什么就突然来了兴趣呢? 首先,从这行代码

  • vue组件historyApiFallback作用详解

    本篇博客主要是详细总结一下vue中的historyApiFallback的作用. 当我们在浏览器中输入一个网址(比如说是:http://www.edit.com),此时会经过dns解析,拿到ip地址然后根据ip地址向该服务器发起请求,服务器接受到请求之后,然后返回相应的结果(html,css,js). 如果我们在前端设置了重定向,此时页面会进行跳转到http://www.edit.com/home,在前端会进行匹配对应的组件然后将其渲染到页面上.此时如果我们刷新页面的话,浏览器会发送新的请求ht

  • Vue编译器源码分析compileToFunctions作用详解

    目录 引言 Vue.prototype.$mount函数体 源码出处 options.delimiters & options.comments compileToFunctions函数逐行分析 createFunction 函数源码 引言 Vue编译器源码分析 接上篇文章我们来分析:compileToFunctions的作用. 经过前面的讲解,我们已经知道了 compileToFunctions 的真正来源你可能会问为什么要弄的这么复杂?为了搞清楚这个问题,我们还需要继续接触完整的代码. 下面

  • SpringMVC视图作用详解

    目录 一.ThymeleafView 二.转发视图 三.重定向视图 四.视图控制器view-controller SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户 SpringMVC视图的种类很多,默认有转发视图和重定向视图 当工程引入jstl的依赖,转发视图会自动转换为JstlView 若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视 图解析器解析之后所得到的是ThymeleafV

  • Mysql中explain作用详解

    一.MYSQL的索引 索引(Index):帮助Mysql高效获取数据的一种数据结构.用于提高查找效率,可以比作字典.可以简单理解为排好序的快速查找的数据结构. 索引的作用:便于查询和排序(所以添加索引会影响where 语句与 order by 排序语句). 在数据之外,数据库还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用数据.这样就可以在这些数据结构上实现高级查找算法.这些数据结构就是索引. 索引本身也很大,不可能全部存储在内存中,所以索引往往以索引文件的形式存储在磁盘上. 我们

  • bootstrap中的 form表单属性role="form"的作用详解

    html 里面的 role 本质上是增强语义性,当现有的HTML标签不能充分表达语义性的时候,就可以借助role来说明.通常这种情况出现在一些自定义的组件上,这样可增强组件的可访问性.可用性和可交互性. role的作用是描述一个非标准的tag的实际作用.比如用div做button,那么设置div 的 role="button",辅助工具就可以认出这实际上是个button 比如, <div role="checkbox" aria-checked="c

随机推荐