JS 生成防篡改水印

news2024/12/18 13:42:51

网页中有水印的需求,今天我们实现手写一个防篡改水印,先看下效果图:

在这里插入图片描述

一、创建class函数

传递一个dom为水印包裹器,有一些监听防篡改的observer,然后实例化的时候创建水印,执行create()方法

class WaterMarker {
  private container: HTMLElement | null;
  private observer_c?: MutationObserver; // 监听水印,防篡改
  private observer_p?: MutationObserver; // 监听水印,防删除
  constructor(container: HTMLElement || null) {
    this.container = container
    this.create() // 初始化
  }
 
 
  // 获取水印元素
  getElement(): HTMLElement | null {
    return document.getElementById(`water_marker`)
  }

  // 延时执行
  async wait(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms))
  }
}

let dom = document.querySelector('#body') as HTMLElement || null
dom ? let waterMarker = new WaterMarker(dom) : ''

二、创建水印dom

这里创建水印dom记得将鼠标指针设置为无效,以免水印dom遮挡画面部分点击区域,‘pointerEvents’ 为 null,这里的 mixBlendMode 混合模式则是为了避免水印和画面的颜色重叠,造成水印不可见。

// 创建水印
  async create(): Promise<void> {
    await this.wait(500)
    let content = `<span style="font-size: 18px">游客</span> <br> <span style="font-size: 18px">Guest</span> <br> 中国传媒大学`
    let el = document.createElement('div') as HTMLElement
    el.style.display = 'inline-block'
    el.style.position = 'absolute'
    el.id = `water_marker`
    el.style.top = '20px'
    el.style.left = '20px'
    el.style.lineHeight = '20px'
    el.style.color = '#fff'
    el.style.fontSize = '14px'
    el.style.textAlign = 'center'
    el.style.fontWeight = 'bold'
    el.style.pointerEvents = 'none'
    el.style.filter = 'opacity(0.75)'
    el.style.textShadow = '1px 1px 0px rgba(0, 0, 0, 0.2),\n' +
      '      1px 2px 0px rgba(0, 0, 0, 0.2),\n' +
      '      1px 3px 0px rgba(0, 0, 0, 0.2)'
    el.style.mixBlendMode = 'difference'
    el.style.zIndex = 10
    el.style.transform = 'rotateZ(-45deg)'
    el.innerHTML = content
    this.container?.appendChild(el)
    // 开始动画
    this.createAnimate(el)
    // 等待一秒开始监听水印篡改,删除
    await this.wait(1000)
    // 监听水印,防篡改
    this.observeC(el)
    // 监听水印,防删除
    this.observeP()
  }

三、给水印添加animate动画,旋转动画

 // 创建动画
  createAnimate(el: HTMLElement): void {
    let delay = 1000 * 6 // 6秒循环一次
    let width = this.container.offsetWidth || 0
    let height = this.container.offsetHeight || 0

    el.animate(
      [
        { transform: `translate(0 ,0) rotateZ(-45deg)` }, // 起始位置
        { transform: `translate(calc(${width - 40}px - 100%), 0) rotateZ(45deg)`}, // 右侧
        { transform: `translate(calc(${width - 40}px - 100%), calc(${height - 40}px - 100%)) rotateZ(45deg)` }, // 底部
        { transform: `translate(0, calc(${height - 40}px - 100%)) rotateZ(-45deg)` }, // 左侧
        { transform: `translate(0, 0) rotateZ(-45deg)`} // 返回起始位置
      ],
      {
        duration: delay,
        iterations: Infinity, // 无限循环
        easing: 'cubic-bezier(.31,.01,1,1.27)',
        delay: 0,
      }
    )
  }

四、水印添加防篡改,防删除

防篡改用MutationObserver监听目标元素的节点、属性、子节点变化达到防篡改的作用
防删除用MutationObserver监听包裹器,判断删除的子节点是否包含水印,达到防删除的作用

这里的option配置有几个属性:

属性名作用
attributes元素节点的属性值变化
characterData元素节点的内容数据发生变化
childList元素节点的子节点的新增和移除
subtree元素深层节点的变化
 // 监听目标元素的变化
  observeC(el: HTMLElement): void {
    let config: MutationObserverInit = { attributes: true, characterData: true, childList: true, subtree: true }
    this.observer_c = new MutationObserver((mutationsList: MutationRecord[]) => {
      for (let mutation of mutationsList) {
        switch (mutation.type) {
          case 'attributes':
          case 'childList':
          case 'characterData':
            alert('请勿篡改水印哦,尊重版权!')
            // 销毁重新创建,这里可以函数防抖下,改变style的时候
            let cb = () => {
             this.destroy()
             this.create()
            }
            debounce(cb, 100)
            break;
          default:
            break;
        }
      }
    });
    this.observer_c.observe(el, config);
  }

  // 监听目标元素的父元素的子节点删除,从而达到监听水印被删除
  observeP() {
    let config: MutationObserverInit = { attributes: true, characterData: true, childList: true, subtree: true }
    this.observer_p = new MutationObserver((mutationsList: MutationRecord[]) => {
      for (let mutation of mutationsList) {
        switch (mutation.type) {
          case 'childList':
          	// 判断删除的子节点中是否包含水印节点
            let removedNodes = Array.from(mutation.removedNodes)
            if (removedNodes.find(node => node.id.includes('water_marker'))) {
              alert('请勿篡改水印哦,尊重版权!')
              // 销毁重新创建
              this.destroy()
              this.create()
            }
            break;
          default:
            break;
        }
      }
    });
    this.observer_p.observe(this.container, config);
  }

五、添加销毁事件

这里要先销毁监听器,再销毁水印dom

  destroy() {
    this.observer_c?.disconnect()
    this.observer_p?.disconnect()
    let el: HTMLElement = this.getElement()
    el? el.remove() : ''
  }

六、拓展

如果涉及到重复,创建dom可修改为canvas创建,这里就不多说了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2261617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

概率论得学习和整理26:EXCEL 关于plot 折线图--频度折线图的一些细节

目录 0 折线图有很多 1 频度折线图 1.1 直接用原始数据做的频度折线图 2 将原始数据生成数据透视表 3 这样可以做出了&#xff0c;频度plot 4 做按某字段汇总&#xff0c;成为累计plot分布 5 修改上面显示效果&#xff0c;做成百分比累计plot频度分布 0 折线图有很多 这…

实现echart大屏动画效果及全屏布局错乱解决方式

如何实现echarts动画效果?如何实现表格或多个垂直布局的柱状图自动滚动效果?如何解决tooltip位置超出屏幕问题,如何解决legend文字过长,布局错乱问题?如何处理饼图的中心图片永远居中? 本文将主要解决以上问题,如有错漏,请指正. 一、大屏动画效果 这里的动画效果主要指&…

pytest入门九:feature

fixture是pytest特有的功能&#xff0c;用以在测试执行前和执行后进行必要的准备和清理工作。使用pytest.fixture标识&#xff0c;定义在函数前面。在你编写测试函数的时候&#xff0c;你可以将此函数名称做为传入参数&#xff0c;pytest将会以依赖注入方式&#xff0c;将该函数…

C# 中的闭包

文章目录 前言一、闭包的基本概念二、匿名函数中的闭包1、定义和使用匿名函数2、匿名函数捕获外部变量3、闭包的生命周期 三、Lambda 表达式中的闭包1、定义和使用 Lambda 表达式2、Lambda 表达式捕获外部变量3、闭包的作用域 四、闭包的应用场景1、事件处理2、异步编程3、迭代…

ChatGPT客户端安装教程(附下载链接)

用惯了各类AI的我们发现每天打开网页还挺不习惯和麻烦&#xff0c;突然发现客户端上架了&#xff0c;懂摸鱼的人都知道这里面的道行有多深&#xff0c;话不多说&#xff0c;开整&#xff01; 以下是ChatGPT客户端的详细安装教程&#xff0c;适用于Windows和Mac系统&#xff1a…

GRE over IPSec 如何应用?如何在ensp上配置GRE over IPSec 实验?

GRE over IPSec应用场景 IPSec VPN本端设备无法感知对端有几个设备 &#xff0c;本端共用一个IPSec SA 。报文封装中没有对端设备的下一跳 &#xff0c;所以无法传输组播、广播和非IP报文 &#xff0c;比如OSPF协议 &#xff0c;导致分支与总部的内部网络之间无法使用OSPF路由…

概率论得学习和整理29: 用EXCEL 描述二项分布

目录 1 关于二项分布的基本内容 2 二项分布的概率 2.1 核心要素 2.2 成功K次的概率&#xff0c;二项分布公式 2.3 期望和方差 2.4 具体试验 2.5 概率质量函数pmf 和cdf 3 二项分布的pmf图的改进 3.1 改进折线图 3.2 如何生成这种竖线图呢 4 不同的二项分布 4.1 p0.…

leetcode 面试经典 150 题:三数之和

链接三数之和题序号11类型数组解题方法排序双指针法难度中等 题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c; 同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三…

【Linux】Nginx一个域名https一个地址配置多个项目【项目实战】

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

【线性代数】理解矩阵乘法的意义(点乘)

刚接触线性代数时&#xff0c;很不理解矩阵乘法的计算规则&#xff0c;为什么规则定义的看起来那么有规律却又莫名其妙&#xff0c;现在参考了一些资料&#xff0c;回过头重新总结下个人对矩阵乘法的理解&#xff08;严格来说是点乘&#xff09;。 理解矩阵和矩阵的乘法&#x…

HTML、CSS表格的斜表头样式设置title 画对角线

我里面有用到layui框架的影响&#xff0c;实际根据你自己的框架来小调下就可以 效果如下 上代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…

29. Three.js案例-自定义平面图形

29. Three.js案例-自定义平面图形 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它利用 WebGL 技术在浏览器中渲染 3D 图形。 构造器 THREE.WebGLRenderer(parameters : object) 参数类型描述parametersobject可选参数对象&…

一条线上的点

给你一个数组 points &#xff0c;其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。 提示&#xff1a; 1 < points.length < 300points[i].length 2-104 < xi, yi < 104points 中的所有点 互不相同 解析&#xff1a;使用斜…

WebRTC服务质量(05)- 重传机制(02) NACK判断丢包

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

八股—Java基础(二)

目录 一. 面向对象 1. 面向对象和面向过程的区别&#xff1f; 2. 面向对象三大特性 3. Java语言是如何实现多态的&#xff1f; 4. 重载&#xff08;Overload&#xff09;和重写&#xff08;Override&#xff09;的区别是什么&#xff1f; 5. 重载的方法能否根据返回值类…

linux ibus rime 中文输入法,快速设置为:默认简体 (****)

本文环境&#xff1a; ubuntu 22.04 直接 apt install ibus-rime 输入法的安全性&#xff0c;人们应该关注吧&#xff01;&#xff01;&#xff1f;&#xff1f; 云输入法&#xff1f;将用户的输入信息传输到云端吗&#xff1f;恐怕很多人的银行账户和密码&#xff0c;早就上…

uniapp使用百度地图配置了key,但是显示Map key not configured

搞了我两天的一个问题。 hbuilderx版本&#xff1a;4.36 问题介绍&#xff1a; 我的项目是公司的项目&#xff0c;需要在H5端使用百度地图&#xff0c;使用vue-cli创建的uniapp&#xff0c;就是uni代码在src里的目录结构。就是使用这种方式才会遇到这个问题。 问题原因&#xf…

ensp 静态路由配置

A公司有广州总部、重庆分部和深圳分部3个办公地点&#xff0c;各分部与总部之间使用路由器互联。广州、重庆、深圳的路由器分别为R1、R2、R3&#xff0c;为路由器配置静态路由&#xff0c;使所有计算机能够互相访问&#xff0c;实训拓扑图如图所示 绘制拓扑图 给pc机配置ip地址…

3分钟读懂数据分析的流程是什么

数据分析是基于商业目的&#xff0c;有目的地进行收集、整理、加工和分析数据&#xff0c;提炼出有价值的 信息的一个过程。整个过程大致可分为五个阶段&#xff0c;具体如下图所示。 1.明确目的和思路 在开展数据分析之前&#xff0c;我们必须要搞清楚几个问题&#xff0c;比…

Python-基于Pygame的小游戏(坦克大战-1.0(世界))(一)

前言:创作背景-《坦克大战》是一款经典的平面射击游戏&#xff0c;最初由日本游戏公司南梦宫于1985年在任天堂FC平台上推出。游戏的主题围绕坦克战斗&#xff0c;玩家的任务是保卫自己的基地&#xff0c;同时摧毁所有敌人的坦克。游戏中有多种地形和敌人类型&#xff0c;玩家可…