前端开发攻略---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>

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

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

相关文章

流程图步骤条

1.结构 <ul class"stepUl"> <li class"stepLi" v-for"(item, index) in stepList" :key"index"> <div class"top"> <p :class"{active: currentState > item.key}">{{ item.value }}…

Gradle 实战 - 启动main函数-ApiHug准备-工具篇-012

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace ApiHug …

【ELK】ELK企业级日志分析系统

搜集日志&#xff1b;日志处理器&#xff1b;索引平台&#xff1b;提供视图化界面&#xff1b;客户端登录 日志收集者&#xff1a;负责监控微服务的日志&#xff0c;并记录 日志存储者&#xff1a;接收日志&#xff0c;写入 日志harbor&#xff1a;负责去连接多个日志收集者&am…

PCL 高斯滤波(C++详细过程版)

目录 一、概述二、代码实现三、结果展示1、滤波前2、滤波后3、对比PCL 高斯滤波(C++详细过程版)由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 高斯滤波在PCL里有现成的调用函数,具体算法原理和实现代码见:

2路音频解码器JR-AD201

音频解码器 详细介绍 JR-AD201 2路音频解码器&#xff0c;支持RF/ASI/IP输入&#xff0c;支持DRA/AC3/EAC3/AAC/MPEG等音频&#xff0c;输出&#xff1a;2路模拟立体声&#xff0c;2路AES/EBU。 产品特点 支持多种输入方式RF/IP/ASI 接口丰富&#xff0c;AES/EBU/模拟立体声/A…

CSS盒模型(详讲)

目录 概述&#xff1a; 内容区&#xff08;content&#xff09;&#xff1a; 内边距&#xff08;paddingj&#xff09;&#xff1a; 前言&#xff1a; 设置内边距&#xff1a; 边框&#xff08;border&#xff09;&#xff1a; 前言&#xff1a; 示例&#xff1a; 外边…

Android开发——布局

LinearLayout RelativeLayout 所谓父子容器&#xff0c;就是嵌套容器时存在的关系。 根据兄弟容器定位需要传入兄弟的id。 通用属性 FrameLayout (覆盖布局&#xff09; TableLayout (表格&#xff09; GridLayout (网格) 子控件属性

【C++学习】深入理解C++异常处理机制:异常类型,捕获和处理策略

文章目录 ♫一.异常的提出♫二.异常的概念♫三.异常的使用♫3.1 异常的抛出和捕获♫3.2.异常的重新抛出♫3.3异常安全♫3.4 异常规范 ♫4.自定义异常体系♫5.C标准库的异常体系♫6.异常的优缺点 ♫一.异常的提出 之前&#xff1a; C语言传统的处理错误的方式与带来的弊端&…

基于SpringBoot的“线上教学平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“线上教学平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 线上教学平台结构图 管理员登录界面图 学员管理界…

深入理解JavaScript - JavaScript中call、apply、bind方法

一、call() / apply() JavaScript中的函数是对象&#xff0c;与其他JavaScript对象一样,JavaScript函数也有方法。其中有两个自带的方法 – call和apply&#xff0c;可以利用这两个方法来间接调用某个函数。 通过一个简单的例子体会一下call和apply的用法&#xff1a; funct…

嵌入式学习54-ARM3

S3c2440中断控制器 内部外设&#xff1a; DMA &#xff1a;&#xff08;直接内存存取&#xff09; Direct Memor…

基于docker的开发者集成环境

docker-compose一键部署开发者环境。 常见的中间件&#xff1a;nginx, mysql, redis, mongo, rabbitmq, nacos, rocketmq, zookeeper等。 GIthub项目地址 1. 下载项目&#xff1a;git clone https://github.com/xhga/docker-develop-env.git 2. 进入文件夹&#xff1a;cd d…

服务器测试之intel E8102CQDA2

这个卡是个双口100G双芯片的卡&#xff0c;QSFP28 单口速率100G&#xff0c;双口200G 1.BIOS下pcie带宽设置 服务器BIOS下支持设置PCIE link width 设置x8x8&#xff0c;否则只能显示一个网口&#xff0c;如下图 E810-2CQDA2需要BIOS下设置该卡槽位pcie slot link width 设置x8…

Paddle实现人脸对比(二)

我之前发过一篇基于孪生网络的人脸对比的文章&#xff0c;这篇文章也到了百度的推荐位置&#xff1a; 但是&#xff0c;效果并不是很好。经过大量的搜索&#xff0c;我发现了一种新的方法&#xff0c;可以非常好的实现人脸对比。 原理分析 我们先训练一个普通的人脸分类模型&…

OpenCV4.10使用形态运算提取水平线和垂直线

目标 在本教程中&#xff0c;您将学习如何&#xff1a; 应用两个非常常见的形态运算符&#xff08;即膨胀和侵蚀&#xff09;&#xff0c;并创建自定义内核&#xff0c;以便在水平轴和垂直轴上提取直线。为此&#xff0c;您将使用以下 OpenCV 函数&#xff1a; erode()dilate…

认识异常(2)

❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&a…

python创建word文档并向word中写数据

一、docx库的安装方法 python创建word文档需要用到docx库&#xff0c;安装命令如下&#xff1a; pip install python-docx 注意&#xff0c;安装的是python-docx。 二、使用方法 使用方法有很多&#xff0c;这里只介绍创建文档并向文档中写入数据。 import docxmydocdocx.Do…

基于生成对抗网络在服装领域的发展脉络和应用趋势

文章目录 1、概述2、深度学习图像生成模型2.1、深度信念网络(Deep belief network&#xff0c;DBN)2.2、变分自编码器(Variational auto-encoder&#xff0c;VAE)2.3、生成对抗网络(Generative adversarial networks&#xff0c;GAN) 3、 模型对比分析4、基于多模态转换的服装图…

nexus搭建maven与docker镜像的私有仓库

引言 通过nexus搭建maven与docker镜像的私有仓库,实现jar包与镜像动态更新、共享、存储。 一、nexus部署 通过docker-compose部署nexus name: java services:#############################环境#############################env-nexus:restart: always## 3.58.1image: so…

代码随想录算法训练营第三十七天| LeetCode 738.单调递增的数字、总结

一、LeetCode 738.单调递增的数字 题目链接/文章讲解/视频讲解&#xff1a;https://programmercarl.com/0738.%E5%8D%95%E8%B0%83%E9%80%92%E5%A2%9E%E7%9A%84%E6%95%B0%E5%AD%97.html 状态&#xff1a;已解决 1.思路 如何求得小于等于N的最大单调递增的整数&#xff1f;98&am…