【VUE】前端实现防篡改的水印

效果

在这里插入图片描述

在这里插入图片描述

水印的作用

图片加水印的操作一般是由后端来完成,有些站点保护的知识产权的类型可能比较多,不仅仅是图片,可能还有视频、文字等等,对于不同类型的对象添加水印后端操作比较复杂,所有有些站点逐步的让前端去进行水印添加的操作。

前端框架

React框架

如果用React框架来进行开发就比较简单,在Ant Design 库里面有一个水印组件Watermark,通过这个组件你可以给一个区域加上一个水印。区域内容没有限制,如图片、文字、视频等等添加水印都是可以的。
在这里插入图片描述

Vue 框架

Ant Design Vue Element UI 暂时没有水印组件。所以需要自己开发,基本思路如下:

  1. 生成水印 :使用canvas.toDataURL()生成base64水印图片数据,将水印图片数据赋值到水印div上。
  2. 防止篡改
    • 监控篡改 : 使用 MutationObserver.observe 监控水印元素、属性、内容、子元素变化,然后改变依赖数据flag.value++;
    • 重新添加水印:定义响应式依赖数据const flag = ref(0);, 使用 watchEffect 自动追踪依赖flag.value;,重新添加水印元素

代码

App.vue

<template><div class="container"><WatermarkComponent text="少莫千华"><div class="content" style="background-color: red;"><img  src="./assets/LA.png"/></div></WatermarkComponent><WatermarkComponent text="少莫千华"><video controls class="video" src= './assets/LA.mp4'></video></WatermarkComponent></div>
</template><script>
import WatermarkComponent from './components/WatermarkComponent.vue'export default {name: 'App',components:{WatermarkComponent}
}
</script><style scoped>
.container{width: 100%;display: flex;justify-content: space-around;position: relative;
}
.content{display: flex;justify-content: center;align-items: center;position: relative;margin: 3px;
}
img{height: 100%;width: 100%;object-fit:cover;
}
video {height: 110%;width: 100%;object-fit:fill;
}
.watermark-container {position: relative;flex-basis: 50%;box-sizing: border-box;
}
video{position: absolute;flex-basis: 50%;box-sizing: border-box;
}#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>

WatermarkComponent.vue

<template><div class="watermark-container" ref="parentRef"><slot></slot><!-- 添加一个div,填充整个区域,设置水印背景,重复 --></div>
</template><script setup>
import { onMounted, onUnmounted,defineProps, ref, watchEffect } from 'vue';
import useWatermarkBg from './useWatermarkBg';const props = defineProps( {text: {type: String,required: true,default: '少莫千华',},fontSize:{type: Number,default: 40,},gap:{type:Number,default:20,},
});
const bg = useWatermarkBg(props);
const parentRef = ref(null);
// 定义一个依赖
const flag = ref(0);
let div;//挂载以后添加水印
//监控元素变化、元素属性变化,防止篡改
//动态生成水印元素div
watchEffect(()=>{flag.value;if(!parentRef.value){return ;}if(div){div.remove();}const {base64,styleSize} = bg.value;div = document.createElement('div');div.style.backgroundImage = `url(${base64})`;div.style.backgroundSize = `${styleSize}px ${styleSize}px`;// 重复平铺div.style.backgroundRepeat = 'repeat'; // 覆盖到同级的上一个元素div.style.zIndex = 9999;// 绝对定位div.style.position = 'absolute';// 设置边距div.style.inset = 0;//div.style.left = 0;//div.style.right = 0;//div.style.top = 0;//div.style.bottom = 100;//将水印添加到 .watermark-container 元素中parentRef.value.appendChild(div);
});onMounted(()=>{//监控元素属性、子元素、内容、元素本身变化let ob =  new MutationObserver((records)=>{console.log(records);for(const record of records) {// 判断删除的节点for(const dom of record.removedNodes) {// 判断节点是不是水印if(dom === div) {//删除水印元素触发 watchEffectconsole.log('删除了水印元素');// 修改依赖值,触发 watchEffect 重新运行flag.value++;return;}}//修改水印元素属性触发 watchEffectif(record.target === div){console.log('修改了水印属性');// 修改依赖值,触发 watchEffect 重新运行flag.value++;return;}//生产环境考虑到其他内容,完善,如 ZIndex 等等}});// 监听 parentRef.value的变化// 监听内容:childList、attributes、subtreeob.observe(parentRef.value,{childList: true,attributes : true,subtree: true,});onUnmounted(()=>{ob && ob.disconnect();//取消监听div = null;});
});</script><!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.wartermark-container{position: relative;
}
</style>

生成水印图像 useWatermarkBg.js

import { computed } from 'vue';export default function useWatermarkBg(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;console.log(canvasSize + 'px');canvas.width = canvasSize;canvas.height = canvasSize;ctx.translate(canvas.width/2, canvas.height/2);//倾斜文本45°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:canvas.toDataURL(),size:canvasSize,styleSize:canvasSize/devicePixelRatio,};});
}

资源

LA.png

在这里插入图片描述

LA.mp4

演讲开始素材

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

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

相关文章

认识所有权

专栏简介&#xff1a;本专栏作为Rust语言的入门级的文章&#xff0c;目的是为了分享关于Rust语言的编程技巧和知识。对于Rust语言&#xff0c;虽然历史没有C、和python历史悠远&#xff0c;但是它的优点可以说是非常的多&#xff0c;既继承了C运行速度&#xff0c;还拥有了Java…

前沿分享-鱼形机器人

可能并不太前沿了&#xff0c;是21年底的新闻了&#xff0c;但是看见了就顺便发一下吧。 大概就是&#xff0c;通过在pH响应型水凝胶中编码不同的膨胀速率而构建了一种环境适应型变形微机器人,让微型机器人直接向癌细胞输送药物从而减轻药物带来副作用。 技术原理是&#xff0c…

拦截器对接口细粒度权限校验

文章目录 一、逻辑分析二、校验规则1.规则类型2.规则划分3.规则配置信息4.规则案例说明5.规则加载 三、拦截器定义1.自定义拦截器2.注册拦截器 四、获取请求参数1.获取get提交方式参数2.获取post提交方式参数&#xff08;1&#xff09;定义RequestWrapper类&#xff08;2&#…

Flink正常消费一段时间后,大量反压,看着像卡住了,但又没有报错。

文章目录 前言一、原因分析二、解决方案 前言 前面我也有提到&#xff0c;发现flink运行一段时间后&#xff0c;不再继续消费的问题。这个问题困扰了我非常久&#xff0c;一开始也很迷茫。又因为比较忙&#xff0c;所以一直没有时间能够去寻找答案&#xff0c;只是通过每天重启…

IDEA中maven项目失效,pom.xml文件橙色/橘色

IDEA中maven项目失效&#xff0c;pom.xml文件橙色/橘色 IDEA中Maven项目失效 IDEA中创建的maven项目中的文件夹都变成普通格式&#xff0c;pom.xml变成橙色 右键点击橙色的pom.xml文件&#xff0c;选择add as maven project maven项目开始重新导入相应依赖&#xff0c;恢复…

字符串查找匹配算法

概述 字符串匹配&#xff08;查找&#xff09;是字符串的一种基本操作&#xff1a;给定带匹配查询的文本串S和目标子串T&#xff0c;T也叫做模式串。在文本S中找到一个和模式T相符的子字符串&#xff0c;并返回该子字符串在文本中的位置。 暴力匹配 Brute Force Algorithm&a…

安全狗V3.512048版本绕过

安全狗安装 安全狗详细安装、遇见无此服务器解决、在windows中命令提示符中进入查看指定文件夹手动启动Apache_安全狗只支持 glibc_2.14 但是服务器是2.17_黑色地带(崛起)的博客-CSDN博客 安全狗 safedogwzApacheV3.5.exe 右键电脑右下角安全狗图标-->选择插件-->安装…

vscode中无法使用git解决方案

1 首先查看git安装目录 where git 2 找到bash.exe 的路径 比如&#xff1a;C:/Users/Wangzd/AppData/Local/Programs/Git/bin/bash 3 找到vscode的配置项setting.json 4 添加 "terminal.integrated.shell.windowns": "C:/Users/Wangzd/AppData/Local/Pr…

架构训练营学习笔记:6-2 微服务基础选型

基础选型 微服务基础设施架构 优先级 其中&#xff0c;核心 就是服务注册、服务发现、服务路由。 模式1-嵌入SDK 模式2-反向代理式 模式3-网络代理式&#xff08;Service Mesh&#xff09; 模式对比 常见微服务框架选择 嵌入SDK-dubbo Spring Cloud 反向代理式 APISIX …

跨境B2B2C多用户购物网站源码快速部署

​ 搭建跨境B2B2C多用户购物网站需要以下步骤&#xff1a; 1. 确定业务模式和定位&#xff1a;确定网站的业务模式&#xff0c;包括跨境B2B2C的商业模式以及目标用户定位。 2. 营业执照和域名注册&#xff1a;根据当地法律要求&#xff0c;注册一家具有法人资格的公司&#xff…

基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

跨尺度预测模式&#xff08;The Model for Prediction Across Scales - MPAS&#xff09;是由洛斯阿拉莫斯实验室和美国国家大气研究中心(NCAR)共同开发&#xff0c;其由3个部分组成&#xff0c;分别称为 MPAS-A&#xff08;大气模型&#xff09;、MPAS-O&#xff08;海洋模型&…

一百四十一、Kettle——kettle8.2在Windows本地开启carte服务以及配置子服务器

一、目的 在kettle建好共享资源库后&#xff0c;为了给在服务器上部署kettle的carte服务躺雷&#xff0c;先在Windows本地测试一下怎么玩carte服务 二、Kettle版本以及在Windows本地安装路径 kettle版本是8.2 pdi-ce-8.2.0.0-342 kettle本地安装路径是D:\j…

全面讲解最小二乘法

常见的最小二乘法我们就不多说了&#xff0c;下面主要介绍一下最小二乘法的一些先进方法。 正则化的最小二乘法 在使用常见的最小二乘法进行回归分析时&#xff0c;常常会遇到过拟合的问题&#xff0c;也就是在训练数据集上表现的很好&#xff0c;但是在测试数据集上表现的很…

【Maven】常用命令、插件管理、私服nexus

【Maven】常用命令、插件管理、私服nexus 常用命令 插件管理 私服nexus Nexus3 配置私服 项目pom中的配置 发布时区分正式版、快照版 常用命令 Maven提供了一系列常用命令&#xff0c;用于构建、测试和管理项目。以下是一些常用的Maven命令示例&#xff1a; mvn clean:…

Cadence学习

Cadence学习 Cadence内容涵盖Cadence主要功能Cadence功能模块Allegro Design Entry CIS 和 OrCAD Capture CIS 的区别Cadence 公司简介Allegro Design Entry CISOrCAD Capture CIS OrCAD中part和database part区别OrCAD中不同页面的连接关系应该怎么处理&#xff08;1&#xff…

【Unity3D】消融特效

1 前言 选中物体消融特效中基于 Shader 实现了消融特效&#xff0c;本文将基于 Shader Graph 实现消融特效&#xff0c;两者原理一样&#xff0c;只是表达方式不同&#xff0c;另外&#xff0c;选中物体消融特效中通过 discard 丢弃片元&#xff0c;本文通过 alpha 测试丢弃片元…

【华秋推荐】物联网入门学习模块 ESP8266

随着全球信息技术的不断进步和普及&#xff0c;物联网成为当今备受关注的技术热点之一。通过物理和数字设备之间的连接来实现自动化和互联互通的网络。无线传感器、云计算和大数据分析等技术&#xff0c;物联网使设备能够相互交流和共享信息&#xff0c;实现智能化的自动化操作…

RocketMQ第二课-核心编程模型以及生产环境最佳实践

一、回顾RocketMQ的消息模型 ​ 上一章节我们从试验整理出了RocketMQ的消息模型&#xff0c;这也是我们使用RocketMQ时最直接的指导。 二、深入理解RocketMQ的消息模型 1、RocketMQ客户端基本流程 <dependency><groupId>org.apache.rocketmq</groupId>&…

数据结构 | 搜索和排序——搜索

目录 一、顺序搜索 二、分析顺序搜索算法 三、二分搜索 四、分析二分搜索算法 五、散列 5.1 散列函数 5.2 处理冲突 5.3 实现映射抽象数据类型 搜索是指从元素集合中找到某个特定元素的算法过程。搜索过程通常返回True或False&#xff0c;分别表示元素是否存在。有时&a…

gradle项目Connection timed out,build时先下载gradle问题download gradle-x.x-bin.zip

IDEA 导入 Gradle 项目&#xff0c;编译的时候会默认下载 配置版本的Gradle.zip问题&#xff0c;一般会下载失败&#xff0c;提示Connection timed out&#xff0c;连接超时。 解决办法&#xff1a; 修改项目根目录下gradle目录下的gradle-wrapper.properties文件&#xff0c;…