基于Vue3水印组件封装:防篡改守护!
基于Vue 3的全新水印通用组件。这款组件不仅功能强大,而且易于集成,能够轻松为您的网页或应用添加自定义水印,有效防止内容被篡改或盗用。
在线查看效果: 原文可查看效果地址
一,编写watermark组件
<template>
<div ref="watermarkContainerRef" class="watermark-container">
<!-- 插槽-->
<slot></slot>
</div>
</template>
<script setup>
import { ref, onMounted, watchEffect, onUnmounted, computed } from "vue";
// 使用 defineProps 定义一个组件的 props,这些 props 描述了组件从父组件接收的属性
const props = defineProps({
// 文本内容,类型为字符串,必须提供,默认值为'张苹果博客'
text: {
type: String,
required: true,
default: '张苹果博客'
},
// 字体大小,类型为数字,默认值为10
fontSize: {
type: Number,
default: 10,
},
// 间距,类型为数字,默认值为1
gap: {
type: Number,
default: 1,
},
// 颜色,类型为字符串,默认值为'rgba(82,75,75,0.58)'
color: {
type: String,
default: 'rgba(82,75,75,0.58)',
}
});
// 定义一个用于绘制水印的函数,这里可以封装一下单独引入。
// 它是一个计算属性,意味着它的值会根据其依赖的 props 的变化而自动重新计算
const waterMarkBg = (props) => {
return computed(() => {
// 创建一个新的 canvas 元素
const canvas = document.createElement("canvas");
// 获取设备的像素比,如果未定义则默认为1
const devicePixelRatio = window.devicePixelRatio || 1;
// 根据像素比计算字体大小
const fontSize = props.fontSize * devicePixelRatio;
// 设置字体样式
const font = fontSize + "px serif";
// 获取 canvas 的 2D 渲染上下文
const ctx = canvas.getContext("2d");
// 设置字体
ctx.font = font;
// 测量文本的宽度
const { width } = ctx.measureText(props.text);
// 计算 canvas 的大小,至少为 60,并根据文本宽度和间距因子进行调整
const canvasSize = Math.max(60, width) * props.gap + devicePixelRatio;
// 设置 canvas 的宽高
canvas.width = canvasSize;
canvas.height = canvasSize;
// 将 canvas 的原点移动到中心
ctx.translate(canvas.width / 2, canvas.height / 2);
// 旋转 canvas 45 度
ctx.rotate((Math.PI / 180) * -45);
// 设置填充颜色
ctx.fillStyle = props.color;
// 设置文本对齐方式和基线
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// 再次设置字体
ctx.font = font;
// 在 canvas 上填充文本
ctx.fillText(props.text, 0, 0);
// 返回一个对象,包含 base64 编码的图片数据、canvas 的大小和样式尺寸
return {
base64: canvas.toDataURL(),
size: canvasSize,
styleSize: canvasSize / devicePixelRatio
};
});
};
// 用于存储 MutationObserver 的变量
let ob;
// 用于存储水印 div 的变量
let div;
// 调用 waterMarkBg 函数获取水印相关的计算属性
const bg = waterMarkBg(props);
// 创建一个 ref 用于存储水印容器的 DOM 引用
const watermarkContainerRef = ref('');
// 创建一个 ref 用于标记水印是否需要重新生成
const flag = ref(0);
// 在组件挂载后执行
onMounted(() => {
// 创建一个新的 MutationObserver,用于监听水印容器的变化
ob = new MutationObserver((records) => {
// 遍历所有的变化记录
for (const record of records) {
// 遍历所有被移除的节点
for (const dom of record.removedNodes) {
// 如果被移除的节点是水印 div,则更新 flag 的值并返回
if (dom === div) {
flag.value++;
return;
}
}
// 如果变化的节点就是水印 div,则更新 flag 的值并返回
if (record.target === div) {
flag.value++;
return;
}
}
});
// 包括子节点的变化、属性的变化以及子树的变化
ob.observe(watermarkContainerRef.value,{
childList:true,
attributes:true,
subtree:true
});
})
//卸载
onUnmounted(()=>{
ob && ob.disconnect();
div=null;
})
// 生成水印
watchEffect(() => {
// 触发 watchEffect 的重新执行
flag.value;
// 如果水印容器没有值,则直接返回,不执行后续操作
if (!watermarkContainerRef.value) {
return;
}
// 如果之前已经存在水印 div,则先移除它
if (div) {
div.remove();
}
// 创建一个新的 div 元素用于作为水印的容器
div = document.createElement('div');
// 从计算属性 bg 中获取 base64 编码的图片数据和样式尺寸
const { base64, styleSize } = bg.value;
// 设置 div 的背景图片为水印图片的 base64 编码
div.style.backgroundImage = `url(${base64})`;
// 设置背景图片的尺寸
div.style.backgroundSize = `${styleSize}px ${styleSize}px`;
// 设置背景图片重复显示
div.style.backgroundRepeat = "repeat";
// 设置水印 div 的 z-index 为 9999,以确保它显示在大多数其他元素之上
div.style.zIndex = 9999;
// 设置水印 div 不响应鼠标事件,如点击、悬停等
div.style.pointerEvents = "none";
// 设置水印 div 的位置为绝对定位
div.style.position = "absolute";
// 使用 inset 属性设置 div 占据整个父容器的空间
div.style.inset = "0";
// 将水印 div 添加到水印容器中
watermarkContainerRef.value.appendChild(div);
});
</script>
<style scoped>
.watermark-container{
position: relative;
}
</style>
二,在页面中引入使用
<template>
<div>
<n-grid>
<n-gi style="margin: 15px" span="6 1025:2 " v-for="(item,index) in 4" :key="index">
<!-- 引入 Watermark-->
<Watermark :gap="gap" :text="text" :fontSize="fontSize" :color="color">
<n-card
v-motion-pop-visible-once
title="标题"
hoverable
>
这是内容 <br>
这是内容 <br>
这是内容 <br>
这是内容 <br>
这是内容 <br>
这是内容 <br>
</n-card>
</Watermark>
</n-gi>
</n-grid>
</div>
</template>
<script setup>
import Watermark from '../components/Watermark.vue'
import {ref} from "vue";
const text=ref('张苹果博客');
const gap=ref(1);
const fontSize=ref('10');
const color=ref('');
</script>
<style scoped>
</style>
三,效果图
基于Vue3水印组件封装:防篡改守护!的更多相关文章
- 基于Volley,Gson封装支持JWT无状态安全验证和数据防篡改的GsonRequest网络请求类
这段时间做新的Android项目的client和和REST API通讯框架架构设计.使用了非常多新技术,终于的方案也相当简洁优雅.client仅仅须要传Java对象,server端返回json字符串, ...
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
Go/Python/Erlang编程语言对比分析及示例 本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...
- [开源] 基于Layui组件封装的后台模版,HG-Layui-UI通用后台管理框架V1.0版
HG框架简介 HG-Layui-UI框架,是基于layui最新版UI搭建的一套通用后台管理框架,借鉴了市面上各大主流框架风格,采用iframe标签页实现,保留了传统开发模式的简单实用性. 为快速开发减 ...
- ve-plus:基于 vue3.x 桌面端UI组件库|vue3组件库
VE-Plus 自研轻量级 vue3.js 桌面pc端UI组件库 经过一个多月的筹划及开发,今天给大家带来一款全新的Vue3桌面端UI组件库VEPlus.新增了35+常用的组件,采用vue3 setu ...
- Vue.js 自定义组件封装实录——基于现有控件的二次封装(以计时器为例)
在本人着手开发一个考试系统的过程中,出现了如下一个需求:制作一个倒计时的控件显示在试卷页面上.本文所记录的就是这样的一个过程. 前期工作 对于这个需求,自然我想到的是有没有现成的组件可以直接使用(本着 ...
- WebApi系列~安全校验中的防篡改和防复用
回到目录 web api越来越火,因为它的跨平台,因为它的简单,因为它支持xml,json等流行的数据协议,我们在开发基于面向服务的API时,有个问题一直在困扰着我们,那就是数据的安全,请求的安全,一 ...
- 基于Ant Design Vue封装一个表单控件
开源代码 https://github.com/naturefwvue/nf-vue3-ant 有缺点本来是写在最后的,但是博文写的似乎有点太长了,估计大家没时间往下看,于是就把有缺点写在前面了,不喜 ...
- HVV奇兵—网页防篡改系统在网络安全实战演习中的妙用(上)
近年来,网络安全实战演习受到各大关基单位的高度关注.对于网络安全实战演习的防守方,防火墙.Web应用防火墙.态势感知.EDR.蜜罐等都是较为常见的防守工具,而网页防篡改系统则鲜有露脸的机会-- 很多人 ...
- 基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用
刚完成一些前端项目的开发,腾出精力来总结一些前端开发的技术点,以及继续完善基于SqlSugar的开发框架循序渐进介绍的系列文章,本篇随笔主要介绍一下基于Vue3+TypeScript的全局对象的注入和 ...
- 【vue3-element-admin 】基于 Vue3 + Vite4 + TypeScript + Element-Plus 从0到1搭建后台管理系统(前后端开源@有来开源组织)
vue3-element-admin 是基于 vue-element-admin 升级的 Vue3 + Element Plus 版本的后台管理前端解决方案,技术栈为 Vue3 + Vite4 + T ...
随机推荐
- 战码先锋直播预告丨参与ArkUI,共建OpenHarmony繁荣生态
OpenAtom OpenHarmony(以下简称"OpenHarmony")工作委员会首度发起「OpenHarmony开源贡献者计划」,旨在鼓励开发者参与OpenHarmony开 ...
- Jchardet——支持检测并输出文件编码方式的组件
简介 Jchardet是OpenAtom OpenHarmony(以下简称"OpenHarmony")系统的一款检测文本编码的组件.当上传一个文件时,组件可以检测并输出该文件中 ...
- Java 包和 API 深度解析:组织代码,避免命名冲突
Java 包和 API Java 中的包 用于将相关的类分组在一起.可以将其视为文件目录中的一个文件夹.我们使用包来避免名称冲突,并编写更易于维护的代码. 包分为两类: 内置包(来自 Java API ...
- 5 个编写高效 Makefile 文件的最佳实践
在软件开发过程中,Makefile是一个非常重要的工具,它可以帮助我们自动化构建.编译.测试和部署.然而,编写高效的Makefile文件并不是一件容易的事情.在本文中,我们将讨论如何编写高效的Make ...
- 深入了解 Golang 条件语句:if、else、else if 和嵌套 if 的实用示例
条件语句 用于根据不同的条件执行不同的操作.Go中的条件可以是真或假.Go支持数学中常见的比较运算符: 小于 < 小于等于 <= 大于 > 大于等于 >= 等于 == 不等于 ...
- Ubuntu部署Django一:环境搭建
前言: Ubuntu系统上部署django,使用的部署方案是 Ubuntu + django + uwsgi + nginx Ubuntu系统版本用的是 ubuntu-20.04.2.0-desk ...
- 域名之A记录,CNAME,NS联系和区别
域名解析中常常涉及:A记录,CNAME,NS 1. A记录 又称IP指向,用户可以在此设置子域名并指向到自己的目标主机地址上,从而实现通过域名找到服务器.说明:指向的目标主机地址类型只能使用IP地址; ...
- 基于 Java 编程生成二维码图片
0x01 准备 (1)软件版本 IntelliJ IDEA 2023.1.3 JDK 18 Tomcat 10.1.11 Maven 3.8.6 (2)技术栈 servlet zxing 谷歌项目 生 ...
- 力扣25(java&python)-K 个一组翻转链表(困难)
题目: 给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表. k 是一个正整数,它的值小于或等于链表的长度.如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺 ...
- NICA 校际交流赛#2 游记
\(1\!:\!15\) 到达考场,检测好网络和电脑. 分配任务,sxshm 打前 \(5\) 题,tcy01_QAQ_ 打 \(6,\!7\) 两题,我打后面的题. \(1\!:\!30\) 显得无 ...