前端开发攻略---Vue实现防篡改水印的效果。删除元素无效!更改元素属性无效!支持图片、元素、视频等等。

news2024/11/24 8:41:38

1、演示

2、水印的目的

  1. 版权保护:水印可以在图片、文档或视频中嵌入作者、品牌或版权所有者的信息,以防止未经授权的复制、传播或使用。当其他人使用带有水印的内容时,可以追溯到原始作者或版权所有者,从而加强版权保护。

  2. 身份识别:水印可以用作作者或品牌的标识符,使观众能够轻松识别内容的来源。这对于在社交媒体上分享内容或在网络上发布作品的个人、摄影师、设计师或公司来说尤为重要。

  3. 品牌宣传:水印可以帮助提升品牌知名度和曝光度。通过在图片或视频中添加品牌标识,品牌可以在内容被分享或传播时获得额外的宣传效果。

  4. 内容跟踪:通过在内容中添加水印,可以跟踪内容的传播和使用情况。这对于了解内容在网络上的传播路径、受众和影响力等信息是有帮助的。

3、实话实说

如果通过我们技术层面要解决这种安全或者是版权之类的问题,只能说起一定的作用,增加那些不怀好意的人操作难度。

要说能够完全防止住,那是不可能的,一定是技术手段和非技术手段相结合,双管齐下。这样才能确保万无一失。

总之:防君子不防小人

 4、API介绍(MutationObserver

MutationObserver API 是 Web API 的一部分,用于监视 DOM 树的变化。它允许开发者注册一个回调函数,该函数在指定的 DOM 节点或子树发生变化时被调用。MutationObserver 是一个强大的工具,可以用于监视并响应 DOM 中的变化,而无需使用传统的事件监听器。

主要的组成部分包括:

  1. MutationObserver 对象:用于观察 DOM 树的变化。通过创建 MutationObserver 的实例并传入一个回调函数,可以开始监视指定节点或节点集合的变化。

  2. 观察目标:要监视的 DOM 节点或节点集合。MutationObserver 可以观察单个节点、节点列表,甚至整个文档的变化。

  3. 回调函数:MutationObserver 注册的回调函数在观察的节点发生变化时被调用。回调函数接收一个 MutationRecord 对象数组作为参数,该数组包含描述每个变化的信息。

  4. 变化记录(MutationRecord):描述 DOM 变化的对象。每个 MutationRecord 包含有关变化类型、受影响的节点、以及相关信息的详细信息。

MutationObserver API 的使用场景包括但不限于:

  • 监视 DOM 中特定元素的属性变化。
  • 监视子节点的添加、移除或替换。
  • 监视文本内容的变化。
  • 实时监视动态加载的内容变化。

通过 MutationObserver,开发者可以更加灵活地监控 DOM 变化,实现更加复杂和高效的 DOM 操作和交互。

5、实现逻辑

1、通过手写组件的方式,将需要添加水印的内容放入组件内

2、通过props传入不同内容,实现自定义水印内容、字体大小、水印之间的间隔等等

3、通过canvas来画出水印文字,最后将canvas画出的内容转换为图片

4、通过MutationObserverAPI来监听水印元素被删除、被修改属性的变化

6、代码

1、使用水印组件的代码

<template>
  <div class="container">
    <Watermark text="版权所有123">
      <div class="item">秘密</div>
    </Watermark>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import Watermark from '@/components/Watermark/index.vue'
</script>

<style scoped lang="scss">
.container {
  width: 100%;
  display: flex;
  justify-content: space-around;
  .item {
    width: 300px;
    height: 300px;
    text-align: center;
    line-height: 300px;
    color: #fff;
    font-size: 50px;
    background-color: #266fff;
  }
}
</style>

2、水印组件代码

<template>
  <div class="watermark" ref="parent">
    <slot></slot>
  </div>
</template>

<script setup>
import directive from '@/directive'
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
const parent = ref(null)
const props = defineProps({
  text: {
    type: String,
    required: true,
    default: 'watermark',
  },
  fontSize: {
    type: Number,
    default: 32,
  },
  // 水印的间隔
  gap: {
    type: Number,
    default: 20,
  },
})
const watermarkBg = props => {
  return computed(() => {
    const canvas = document.createElement('canvas')
    // 视口分辨率 确保当窗口大小变化时 画出的内容不模糊
    const devicePixelRatio = window.devicePixelRatio || 1
    const fontSize = props.fontSize * devicePixelRatio
    const font = fontSize + 'px serif'
    const ctx = canvas.getContext('2d')
    // 获取文字宽度
    ctx.font = font
    const { width } = ctx.measureText(props.text)
    const canvasSize = Math.max(100, width) + props.gap * devicePixelRatio
    canvas.width = canvasSize
    canvas.height = canvasSize
    ctx.translate(canvas.width / 2, canvas.height / 2)
    ctx.rotate((Math.PI / 180) * -45)
    ctx.fillStyle = 'rgba(0,0,0,0.3)'
    ctx.font = font
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.fillText(props.text, 0, 0)
    return {
      // 转换为base64格式的图片
      base64: canvas.toDataURL(),
      size: canvasSize / devicePixelRatio,
    }
  })
}
const bg = watermarkBg(props)

// 重置水印
// 如果把水印删掉了,就重新调用这个方法 生成一个新的div
// 如果把水印的样式改了,重新调用这个方法,生成一个新的div
// 因此这个函数可能会反复调用 造成多个水印的生成
let div = null
function resetWatermark() {
  if (!parent.value) return
  // 清除div防止生成多个水印
  if (div) {
    div.remove()
  }
  const { base64, size } = bg.value
  div = document.createElement('div')
  div.style.position = 'absolute'
  div.style.backgroundImage = `url(${base64})`
  div.style.backgroundSize = `${size}px ${size}px`
  div.style.backgroundRepeat = 'repeat'
  div.style.zIndex = 999
  // 实现点击穿透
  div.style.pointerEvents = 'none'
  div.style.inset = 0
  parent.value.appendChild(div)
}

// 生成水印的元素什么时候调用
// 1、onMounted的时候
onMounted(() => {
  // 首次生成水印
  resetWatermark()
  // 观察水印元素
  ob.observe(parent.value, {
    // 观察父元素上所有的子节点
    childList: true,
    // 观察父元素上所有的子节点的子节点
    subtree: true,
    // 观察父元素身上的属性变化
    attributes: true,
  })
})

// 2、当被删除或修改样式的时候
// 这个观察器在当元素发生变化的时候执行
const ob = new MutationObserver(entries => {
  for (const entry of entries) {
    // 处理删除
    for (const node of entry.removedNodes) {
      if (node === div) {
        resetWatermark()
      }
    }
    // 处理修改
    if (entry.target === div) {
      resetWatermark()
    }
  }
})

// 注意细节,在页面卸载的时候取消观察
onUnmounted(() => {
  ob.disconnect()
})
</script>

<style scoped lang="scss">
.watermark {
  position: relative;
}
</style>

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

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

相关文章

windows 更新显卡

下载网址&#xff1a;NVIDIA GeForce 驱动程序 - N 卡驱动 | NVIDIA 选择本地显卡的型号

spring高级篇(一)

1、ApplicationContext与BeanFactory BeanFactory是ApplicationContext的父级接口&#xff1a;&#xff08;citlaltu查看类关系图&#xff09; 在springboot的启动类中&#xff0c;我们通过SpringApplication.run方法拿到的是继承了ApplicationContext的ConfigurableApplicatio…

【前缀合】Leetcode 连续数组

题目解析 525. 连续数组 寻找一个子数组&#xff0c;这个子数组中包含相同数目的0和1&#xff0c;但是这个子数组需要最长的 算法讲解 只需在[0,i]寻找一段区间使得这一段区间的和也等于sum即可 细节问题&#xff1a;1. 这里的哈希表的value存的是下标&#xff0c;因为需要找…

ccframe系统的链路追踪,用户ID追踪的实现

需求 之前ccframe cloud V1用的是springcloud微服务&#xff0c;只需要在header将jwttoken一直传下去就没事&#xff0c;最近弄V2转dubbo发现用户id没有自动保存进数据库表。于是开始研究dubbo如何追踪&#xff0c;顺便把链路追踪ID的问题给一并解决掉。 理论 MDC MDC&…

TSINGSEE青犀AI智能分析网关V4吸烟/抽烟检测算法介绍及应用

抽烟检测AI算法是一种基于计算机视觉和深度学习技术的先进工具&#xff0c;旨在准确识别并监测个体是否抽烟。该算法通过训练大量图像数据&#xff0c;使模型能够识别出抽烟行为的关键特征&#xff0c;如烟雾、手部动作和口部形态等。 在原理上&#xff0c;抽烟检测AI算法主要…

跟TED演讲学英文:The dark side of competition in AI by Liv Boeree

The dark side of competition in AI Link: https://www.ted.com/talks/liv_boeree_the_dark_side_of_competition_in_ai Speaker:Liv Boeree Date: October 2023 文章目录 The dark side of competition in AIIntroductionVocabularyTranscriptSummary后记 Introduction Co…

微服务项目——谷粒商城

文章目录 一、项目简介&#xff08;一&#xff09;完整的微服务架构微服务划分图&#xff08;二&#xff09;电商模式1.B2B 模式2.B2C 模式3.C2B 模式4.C2C 模式5.o2o 模式2.谷粒商城 &#xff08;三&#xff09;项目技术&特色&#xff08;四&#xff09;项目前置要求 二、…

Vue3(二):报错调试,vue3响应式原理、computed和watch,ref,props,接口

一、准备工作调试 跟着张天禹老师看前几集的时候可能会遇到如下问题&#xff1a; 1.下载插件&#xff1a;Vue Language Features (Volar)或者直接下载vue-offical 2.npm run serve时运行时出现错误&#xff1a;Error: vitejs/plugin-vue requires vue (&#xff1e;3.2.13) …

基于java+springboot+vue实现的居家养老健康管理系统(文末源码+Lw)23-313

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装智慧社区居家养老健康管理系统软件来发挥其高效地信息处理…

Filebeat+Kafka+ELK 的服务部署

一. kafka 架构深入 1.1 Kafka 工作流程及文件存储机制 Kafka 中消息是以 topic 进行分类的&#xff0c;生产者生产消息&#xff0c;消费者消费消息&#xff0c;都是面向 topic 的。 topic 是逻辑上的概念&#xff0c;而 partition 是物理上的概念&#xff0c;每个 partit…

B004-表达式 类型转换 运算符

目录 表达式数据类型转换自动转换强制转换 运算符数学运算符自增自减运算符i与 i的区别 赋值运算符比较运算符位运算符(了解)逻辑运算符三目运算符 表达式 /*** 表达式定义&#xff1a;由常量 变量 运算符 括号组成的算式&#xff0c;为了按照一定的运算规则计算出结果值* 括…

二叉搜索树--搜索二维矩阵 II

题目描述 编写一个高效的算法来搜索 m * n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,…

基于springboot实现桂林旅游景点导游平台管理系统【项目源码+论文说明】计算机毕业设计

基于springboot实现桂林旅游景点导游平台管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了桂林旅游景点导游平台的开发全过程。通过分析桂林旅游景点导游平台管理的不足&#xff0c;创建了一个计算…

洛谷P1109 学生分组

#先看题目 题目描述 有 n 组学生&#xff0c;给出初始时每组中的学生个数&#xff0c;再给出每组学生人数的上界 R 和下界 L (L≤R)&#xff0c;每次你可以在某组中选出一个学生把他安排到另外一组中&#xff0c;问最少要多少次才可以使 N 组学生的人数都在 [L,R] 中。 输入…

echarts坐标轴、轴线、刻度、刻度标签

坐标轴 x、y轴 x 轴和 y 轴都由轴线、刻度、刻度标签、轴标题四个部分组成。部分图表中还会有网格线来帮助查看和计算数据 普通的二维数据坐标系都有x轴和y轴&#xff0c;通常情况下&#xff0c;x轴显示在图表底部&#xff0c;y轴显示在左侧&#xff0c;一般配置如下&#xf…

[面向对象] 单例模式与工厂模式

单例模式 是一种创建模式&#xff0c;保证一个类只有一个实例&#xff0c;且提供访问实例的全局节点。 工厂模式 面向对象其中的三大原则&#xff1a; 单一职责&#xff1a;一个类只有一个职责&#xff08;Game类负责什么时候创建英雄机&#xff0c;而不需要知道创建英雄机要…

【Linux学习笔记】安卓运行C可执行文件No such file or directory

文章目录 开发环境运行失败现象解决办法方法一&#xff1a;使用静态库方法二&#xff1a;使用动态库创建lib查找依赖库复制需要注意的事情 开发环境 开发板&#xff1a;正点原子RK3568开发板安卓版本&#xff1a;11可执行程序命名&#xff1a;ledApp需加载模块&#xff1a;dts…

npm命令卡在reify:eslint: timing reifyNode:node_modules/webpack Completed in 475ms不动

1.现象 执行npm install命令时&#xff0c;没有报错&#xff0c;卡在reify:eslint: timing reifyNode:node_modules/webpack Completed in 475ms不动 2.解决办法 &#xff08;1&#xff09;更换淘宝镜像源 原淘宝 npm 域名http://npm.taobao.org 和 http://registry.npm.ta…

Day 39:动态规划 LeedCode 62.不同路径 63. 不同路径 II

62. 不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#…

C语言:约瑟夫环问题详解

前言 哈喽&#xff0c;宝子们&#xff01;本期为大家带来一道C语言循环链表的经典算法题&#xff08;约瑟夫环&#xff09;。 目录 1.什么是约瑟夫环2.解决方案思路3.创建链表头结点4.创建循环链表5.删除链表6.完整代码实现 1.什么是约瑟夫环 据说著名历史学家Josephus有过以下…