【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.hqwc.cn/news/55615.html

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

相关文章

Redhat Linux 安装MySQL安装手册

Redhat安装MySQL安装手册 1 下载2 上传服务器、解压并安装3 安装安装过程1&#xff1a;MySQL-shared-5.6.51-1.el7.x86_64.rpm安装过程2&#xff1a;MySQL-shared-compat-5.6.51-1.el7.x86_64.rpm安装过程3&#xff1a;MySQL-server-5.6.51-1.el7.x86_64.rpm安装过程4&#xff…

奥威BI—数字化转型首选,以数据驱动企业发展

奥威BI系统BI方案可以迅速构建企业级大数据分析平台&#xff0c;可以将大量数据转化为直观、易于理解的图表和图形&#xff0c;推动和促进数字化转型的进程&#xff0c;帮助企业更好地了解自身的运营状况&#xff0c;及时发现问题并采取相应的措施&#xff0c;提高运营效率和质…

Setup Factory Crack,设置Factory项目快速入门

Setup Factory Crack,设置Factory项目快速入门 Setup Factory为开发人员提供了一种无需学习专有脚本语言即可创建灵活安装系统的解决方案。Setup Factory提供开发人员所需的自定义和高级控制功能&#xff0c;所有这些功能都来自Setup Factory Visual Design Environment。您甚至…

Nginx可视化Nginx-gui

Github&#xff1a;GitHub - onlyGuo/nginx-gui: Nginx GUI Manager 运行方式支持docker、window 下载后压缩&#xff0c;直接运行startup.bat 默认账号密码&#xff1a;admin/admin

产品体系架构202308版

1.前言 当我们不断向前奔跑时&#xff0c;需要回头压实走过的路。不断扩张的同时把相应的内容沉淀下来&#xff0c;为后续的发展铺垫基石。 不知从何时起&#xff0c;产品的架构就面向了微服务/中台化/前后端分离/低代码化/分布式/智能化/运行可观测化的综合体&#xff0c;让…

uni-app:实现列表单选功能

效果图&#xff1a; 核心解析&#xff1a; 一、 <view class"item_all" v-for"(item, index) in info" :key"index"><view classposition parameter-info text-over :classitem.checked?"checked_parameter":""…

C++学习——认识什么是STL以及string类的使用

一&#xff1a;认识STL 1.什么是STL 在日常的程序编写当中&#xff0c;假如我们需要交换两个数据就必须手动书写一个交换函数&#xff0c;之后再进行传参。这样才可以实现两个数据的交换。在很多情况下也是如此&#xff0c;我们通常需要的功能还得自己来写&#xff0c;写完之后…

node笔记——调用免费qq的smtp发送html格式邮箱

文章目录 ⭐前言⭐smtp授权码获取⭐nodemailer⭐postman验证接口⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于node调用免费qq的smtp发送邮箱。 node系列往期文章 node_windows环境变量配置 node_npm发布包 linux_配置node node_nvm安装配置 node笔记_h…

24届近5年重庆邮电大学自动化考研院校分析

今天给大家带来的是重庆邮电大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、重庆邮电大学 学校简介 重庆邮电大学简称"重邮"&#xff0c;坐落于直辖市-重庆市&#xff0c;入选国家"中西部高校基础能力建设工程”、国家“卓越工程师教育培养计划…

Flutter 文件上传(七牛云)简单封装

前言&#xff1a;记录了七牛云上传图片的简单封装、若有不足 欢迎指正。 开始前准备&#xff1a; A、七牛sdk版本一定要和dart版本相对应&#xff08;推荐用any方式、让其自己去匹配&#xff09;&#xff1b; qiniu_flutter_sdk: any B、七牛上传文件所需的参数&#xff1a; …

基于springboot+vue的房屋租赁系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

插入排序讲解

插入排序&#xff08;Insertion-Sort&#xff09;一般也被称为直接插入排序。对于少量元素的排序&#xff0c;它是一个有效的算法。插入排序是一种最简单的排序方法&#xff0c;它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而一个新的、记录数增1的有序表…