Vue3.0 实现不可篡改水印

文章介绍了如何使用Vue开发一个可配置且不可篡改的多行水印组件,通过Canvas生成并应用水印到页面上,同时实现动态监听防止内容被修改。
摘要由CSDN通过智能技术生成

水印要求

要求实现多行水印展示效果,并且不可被篡改,水印内容可配置

实现效果

实现思路

1.首先需要一个水印生成的hook

2.需要一个watermark.vue组件

3.将watermark组件使用到需要使用的地方

代码如下:

1.hook(useWatermarkBg.js)
import { computed } from "vue";
export default function useWatermarkBg(props) {
	// console.log(props);
	return computed(() => {
		// 创建一个 canvas
		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(200, width) + props.gap * devicePixelRatio;
		canvas.width = canvasSize;
		canvas.height = canvasSize;
		ctx.translate(canvas.width / 2, canvas.height / 2);
		// 旋转 45 度让文字变倾斜
		ctx.rotate((Math.PI / 180) * -25);
		ctx.fillStyle = "rgba(0, 0, 0, 0.25)";
		ctx.font = font;
		ctx.textAlign = "center";
		ctx.textBaseline = "middle";

		// 获取行高
		const lineHeight = 21;

		// 计算水印在y轴上的初始位置
		let initY = (canvas.height - (16 * props.text.length + (props.text.length - 1) * 5)) / 2;
		initY = initY < 0 ? 0 : initY;
		for (let i = 0; i < props.text.length; i++) {
			if (props.text[i] && props.text[i] != "") {
				ctx.fillText(props.text[i], canvas.width / props.text.length, initY + lineHeight * i);
			}
		}
// 将需要返回的内容return出去
		return {
			base64: canvas.toDataURL(), // 返回一个base64格式水印图片
			size: canvasSize,
			styleSize: canvasSize / devicePixelRatio
		};
	});
}
2.watermark.vue组件
<template>
	<div class="watermark-container" ref="parentRef">
		<slot></slot>
	</div>
</template>

<script setup>
import { onMounted, onUnmounted, ref, watchEffect } from "vue";
import useWatermarkBg from "./useWatermarkBg";
import pinia from "@/store/index.js";
import { useUserStore } from "@/store/store.js";
const useUser = useUserStore(pinia);
const props = defineProps({
// 可配置的水印内容
	text: {
		type: Array,
		default: () => {
			return [];
		}
	},
	fontSize: {
		type: Number,
		default: 18
	},
	gap: {
		type: Number,
		default: 70
	}
});
const bg = useWatermarkBg(props);
const parentRef = ref(null);
const flag = ref(0); // 声明一个依赖
let div;
watchEffect(() => {
	flag.value; // 将依赖放在 watchEffect 里
	if (!parentRef.value) {
		return;
	}
	if (div) {
		div.remove();
	}
	const { base64, styleSize } = bg.value;
	useUser.setWaterMark(base64);
	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.pointerEvents = "none";
	parentRef.value.appendChild(div);
});
let ob;
// 防篡改重要步骤
onMounted(() => {
    // 监听浏览器dom操做变化
	ob = new MutationObserver(records => {
		for (const record of records) {
			for (const dom of record.removedNodes) {
				if (dom === div) {
					flag.value++; // 删除节点的时候更新依赖
					return;
				}
			}
			if (record.target === div) {
				flag.value++; // 修改属性的时候更新依赖
				return;
			}
		}
	});
// 启用监听
	ob.observe(parentRef.value, {
		childList: true,
		attributes: true,
		subtree: true
	});
});
// 销毁监听
onUnmounted(() => {
	ob && ob.disconnect();
	div = null;
});
</script>
<style lang="less" scoped>
.watermark-container {
	width: 100%;
	height: 100%;
}
</style>
3.使用组件

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值