当前位置: 首页 > news >正文

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

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 || 1const fontSize = props.fontSize * devicePixelRatioconst font = fontSize + 'px serif'const ctx = canvas.getContext('2d')// 获取文字宽度ctx.font = fontconst { width } = ctx.measureText(props.text)const canvasSize = Math.max(100, width) + props.gap * devicePixelRatiocanvas.width = canvasSizecanvas.height = canvasSizectx.translate(canvas.width / 2, canvas.height / 2)ctx.rotate((Math.PI / 180) * -45)ctx.fillStyle = 'rgba(0,0,0,0.3)'ctx.font = fontctx.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.valuediv = 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 = 0parent.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>

相关文章:

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

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

在Go语言中复制sync类型

sync包提供了基本的同步原语,例如互斥锁、条件变量和等待组。对于所有这些类型,有一个硬性规则要遵循:它们永远不应该被复制。让我们来理解下这个原理和可能发生的问题。 我们将创建一个线程安全的数据结构来存储计数器。它将包含一个map[string]int,表示每个计数器的当前值…...

Golang | Leetcode Golang题解之第25题K个一组翻转链表

题目&#xff1a; 题解&#xff1a; func reverseKGroup(head *ListNode, k int) *ListNode {hair : &ListNode{Next: head}pre : hairfor head ! nil {tail : prefor i : 0; i < k; i {tail tail.Nextif tail nil {return hair.Next}}nex : tail.Nexthead, tail my…...

【初学】前后端flask+vue组合GET案例

【CSDN 目录配置很不好用】 一、python配置 pip install flaskpip install flask-cors 二、vue配置 1.下载node.js 2.安装node.js 3.测试 node -v4.在vue项目文件夹中创建vue项目 npm create vue@latest第一次会安装一个东西,然后输入名称,一路回车 ✔ Project name…...

计算机科学与技术CS考研408资料

在github上整理了考研的一些资料&#xff1a; 内容包括&#xff1a; 参考书数据结构、组成原理、操作系统、计算机网络.408笔记PDF408思维导图408真题2009-2021真题无logo版408真题2029-2023王道真题&#xff08;持续更新&#xff09;历年真题考频统计灰灰考研择校&#xff0…...

ACID模型是什么

ACID模型是什么 ACID模型是数据库管理系统中保证事务处理安全性的一组特性。ACID是原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;和持久性&#xff08;Durability&#xff09;四个英文单词的…...

【Linux】基础IO----理解缓冲区

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;理解缓冲区 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持。早安! > 专栏选自&#xff1a;Linux初阶 > 望…...

java学习之路-继承

文章目录 前言 目录 1.1继承的概念 1.2继承有什么好处&#xff0c;为何要继承 1.3继承的语句 1.4父类成员的访问 1.4.1 子类中访问父类的成员变量 1.4.2 子类中访问父类的成员方法 1.5 super关键字 2.子类构造方法 2.1如何创建构造方法 2.2创建构造方法 3.super和this 【相同点…...

Linux系统——Elasticsearch企业级日志分析系统

目录 前言 一、ELK概述 1.ELK简介 2.ELK特点 3.为什么要使用ELK 4.完整日志系统基本特征 5.ELK工作原理 6.Elasticsearch介绍 6.1Elasticsearch概述 6.2Elasticsearch核心概念 7.Logstash介绍 7.1Logstash简介 7.2Logstash主要组件 8.Kibana介绍 8.1Kibana简介 …...

多协议接入视频汇聚EasyCVR平台vs.RTSP安防视频EasyNVR平台:设备分组的区别

EasyCVR视频融合云平台则是旭帆科技TSINGSEE青犀旗下支持多协议接入的视频汇聚融合共享智能平台。平台可支持的接入协议比EasyNVR丰富&#xff0c;包括主流标准协议&#xff0c;有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海…...

Spring Security Oauth2 之 理解OAuth 2.0授权流程

1. Oauth 定义 1.1 角色 OAuth定义了四个角色&#xff1a; 资源所有者 一个能够授权访问受保护资源的实体。当资源所有者是一个人时&#xff0c;它被称为最终用户。 资源服务器 托管受保护资源的服务器能够使用访问令牌接受和响应受保护的资源请求。 客户 代表资源所有…...

mysql题目4

tj11&#xff1a; select count(*) 员工总人数 from tb_dept a join tb_employee b on a.deptnob.deptno where a.dname 市场部...

GFS部署实验

目录 1、部署环境 ​编辑 2、更改节点名称 3、准备环境 4、磁盘分区&#xff0c;并挂载 5. 做主机映射--/etc/hosts/ 6. 复制脚本文件 7. 执行脚本完成分区 8. 安装客户端软件 1. 安装解压源包 2. 创建gfs 3. 安装 gfs 4. 开启服务 9、 添加节点到存储信任池中 1…...

最前沿・量子退火建模方法(1) : subQUBO讲解和python实现

前言 量子退火机在小规模问题上的效果得到了有效验证&#xff0c;但是由于物理量子比特的大规模制备以及噪声的影响&#xff0c;还没有办法再大规模的场景下应用。 这时候就需要我们思考&#xff0c;如何通过软件的方法怎么样把大的问题分解成小的问题&#xff0c;以便通过现在…...

如何在Linux部署MeterSphere并实现公网访问进行远程测试工作

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…...

postgis导入shp数据时“dbf file (.dbf) can not be opened.“

作者进行矢量数据导入数据库中出现上述报错 导致报错原因 导入的shp文件路径太深导入的shp文件名称或路径中有中文将需要导入数据的shp 文件、dbf 文件、prj 等文件放在到同一个文件夹内&#xff0c;且名字要一致&#xff1b;导入失败&#xff1a; 导入成功&#xff1a;...

StarUML笔记之从C++代码生成UML图

StarUML笔记之从C代码生成UML图 —— 2024-04-14 文章目录 StarUML笔记之从C代码生成UML图1.安装C插件2.准备好一个C代码文件放某个路径下3.点击Reverse Code选择项目文件夹4.拖动(Class)到中间画面可以形成UML5.另外一种方式&#xff1a;双击Type Hierarchy&#xff0c;然后…...

sizeof()和strlen

一、什么是sizeof() sizeof()是一个在C和C中广泛使用的操作符&#xff0c;用于计算数据类型或变量所占内存的字节数。它返回一个size_t类型的值&#xff0c;表示其操作数所占的字节数。 在使用时&#xff0c;sizeof()可以接收一个数据类型作为参数&#xff0c;也可以接收一个…...

Python学习笔记13 - 元组

什么是元组 元组的创建方式 为什么要将元组设计为不可变序列&#xff1f; 元组的遍历...

[leetcode]remove-duplicates-from-sorted-list-ii

. - 力扣&#xff08;LeetCode&#xff09; 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,5]示例 2&…...

EDK II代码质量门禁报告:全面解析门禁检查结果与最佳实践

EDK II代码质量门禁报告&#xff1a;全面解析门禁检查结果与最佳实践 【免费下载链接】edk2 EDK II 项目地址: https://gitcode.com/gh_mirrors/ed/edk2 EDK II作为现代、功能丰富的跨平台UEFI和PI规范固件开发环境&#xff0c;其代码质量门禁系统是确保固件可靠性和安全…...

想给西安碑林、雁塔等区旧房装修?知名靠谱装修公司在哪找?

在西安碑林、雁塔等区拥有一套旧房&#xff0c;想要进行装修&#xff0c;却不知道如何找到知名靠谱的装修公司&#xff1f;别担心&#xff0c;本文将为你详细介绍选择装修公司的方法&#xff0c;并重点推荐西安王师傅装修工程有限公司&#xff0c;为你的旧房装修之旅提供可靠的…...

告别复杂配置!5分钟掌握OCAT:OpenCore图形化配置神器

告别复杂配置&#xff01;5分钟掌握OCAT&#xff1a;OpenCore图形化配置神器 【免费下载链接】OCAuxiliaryTools Cross-platform GUI management tools for OpenCore&#xff08;OCAT&#xff09; 项目地址: https://gitcode.com/gh_mirrors/oc/OCAuxiliaryTools 如果你…...

rBase64:嵌入式系统零堆分配BASE64编解码库

1. rBase64 库深度解析&#xff1a;面向嵌入式系统的高性能 BASE64 编解码实现BASE64 是一种将任意二进制数据映射为 ASCII 字符子集的编码方案&#xff0c;广泛应用于嵌入式通信协议&#xff08;如 MQTT payload、HTTP Basic Auth、CoAP 传输&#xff09;、固件 OTA 升级包签名…...

OpenClaw任务编排:GLM-4.7-Flash复杂流程设计

OpenClaw任务编排&#xff1a;GLM-4.7-Flash复杂流程设计 1. 为什么需要任务编排 去年我接手了一个市场分析项目&#xff0c;需要每周手动收集竞品动态并生成报告。重复性的复制粘贴和格式调整消耗了大量时间&#xff0c;直到发现OpenClaw可以通过编排GLM-4.7-Flash模型实现全…...

MindSpore mint 模块学习

1. 模块概述mindspore.mint是 MindSpore 框架提供的一个功能接口子模块&#xff0c;旨在提供大量与业界主流深度学习框架&#xff08;如 PyTorch&#xff09;保持一致的 functional、nn、优化器等 API。使熟悉主流框架的用户能够快速上手。性能特点&#xff1a;在图编译模式为 …...

lychee-rerank-mm惊艳效果集:Qwen2.5-VL底座下BF16高精度打分可视化

lychee-rerank-mm惊艳效果集&#xff1a;Qwen2.5-VL底座下BF16高精度打分可视化 想象一下&#xff0c;你有一个包含数百张图片的图库&#xff0c;想快速找出所有“夕阳下的海边剪影”照片。传统方法要么靠记忆&#xff0c;要么一张张翻看&#xff0c;费时费力。现在&#xff0…...

关于腾讯广告算法大赛2025项目分析1 - dataset.py

把原始 jsonl 用户行为序列&#xff0c;转成模型能直接吃的张量tensor和特征字典 一、整体定位 MyDataset 读取训练数据&#xff0c;产出: 用户序列 seq正样本 pos负样本 negtoken 类型各类特征时间特征相关原始时间戳 MyTestDataset 读取测试/推理数据&#xff0c;产出 用户序…...

原子操作的实现原理

在并发编程、操作系统与计算机体系结构中&#xff0c;原子操作是保证数据安全、避免竞态条件的基石。它的核心特性是不可中断、不可分割&#xff0c;操作要么完整执行&#xff0c;要么完全不执行&#xff0c;绝不会出现中间状态。本文将从定义出发&#xff0c;逐层拆解原子操作…...

别再只调参了!深入RepVgg设计思想,用CCFF模块优化你的模型特征融合效率

深入解析CCFF模块&#xff1a;用RepVgg思想重构跨尺度特征融合技术 在计算机视觉领域&#xff0c;特征融合一直是提升模型性能的关键环节。传统方法如FPN、PANet虽然有效&#xff0c;但在实时性要求高的场景下往往成为计算瓶颈。今天我们要探讨的CCFF&#xff08;Cross-scale C…...