前端防篡改水印

本文将介绍一种前端防篡改的水印实现方式(防君子不防小人)

环境 :vite,vue3,node 18.20.8

一、实现水印

使用canvas画布实现一个水印背景图useWatermarkBg,该水印接收三个参数text:水印文字,fontSize:字体大小,gap: 字体间距

vue 复制代码
import { computed } from "vue";
export default function useWatermarkBg(props) {
    return computed(() => {
        const canvas = document.createElement("canvas");
        // 显示倍率
        const dpr = window.devicePixelRatio || 1;
        const fontSize = props.fontSize * dpr;
        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 * dpr;
        // 设置画板大小
        canvas.width = canvasSize;
        canvas.height = canvasSize;
        ctx.translate(canvas.width / 2, canvas.height / 2);
        ctx.rotate((Math.PI / 180) * -45); // 倒序旋转-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 / dpr,
        };
    });
};

二、实现水印的防篡改

使用MutationObserver监听需要添加水印的元素,在水印被删除或者修改时重新插入水印元素,实现水印的防篡改功能,具体实现代码如下:

vue 复制代码
<template>
  <div class="watermark-container" ref="parentRef">
    <slot></slot>
  </div>
</template>

<script setup>
import useWatermarkBg from "./useWatermarkBg";
import { ref, onMounted, onUnmounted } from "vue";
const props = defineProps({
  text: {
    type: String,
    required: true,
    default: "watermark",
  },
  fontSize: {
    type: Number,
    default: 40,
  },
  gap: {
    type: Number,
    default: 20,
  },
});
const parentRef = ref(null);
const bg = useWatermarkBg(props);
let div;
// 重置水印
const resetWatermark = () => {
  if (!parentRef.value) return;
  if (div) {
    div.remove();
  }
  const { base64, size } = bg.value;
  div = 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 = 9999;
  div.style.inset = 0;
  div.style.pointerEvents = "none";
  parentRef.value.appendChild(div);
};
const ob = new MutationObserver((entries) => {
  for (const entry of entries) {
    // 处理div被删除的情况
    for (const node of entry.removedNodes) {
      if (node === div) {
        resetWatermark();
        return;
      }
    }
    // 处理div被修改的情况
    if (entry.target === div) {
      resetWatermark();
    }
  }
});
onMounted(() => {
  resetWatermark();
  // 监听parentRef的修改
  ob.observe(parentRef.value, {
    childList: true, //子元素
    subtree: true, //子树
    attributes: true, //属性
  });
});
onUnmounted(() => {
  ob.disconnect();
});
</script>

<style scoped>
.watermark-container {
  position: relative;
}
</style>

三、水印使用

vue 复制代码
<script setup>
import Watermark from "./components/Watermark.vue";
</script>

<template>
  <Watermark text="前端防篡改水印" style="background-color: beige">
    <div class="content"></div>
  </Watermark>
</template>

<style scoped>
.content {
  width: 100vw;
  height: 100vh;
}
</style>

附上完整代码地址:gitee.com/TriF/tamper...

相关推荐
Python私教7 小时前
Pure-Admin-Thin 深度解析:完整版和精简版到底怎么选?
vue.js·人工智能·开源
ayqy贾杰9 小时前
Cursor SDK发布!开发者可直接搬走其内核
前端·vue.js·面试
李白的天不白10 小时前
vue 数据格式问题
前端·vue.js·windows
小白蒋博客10 小时前
【ai开发段永平投资理财的知识图谱网站】第一天:搭 Vite + Vue 项目,跑通 Hello World
vue.js·人工智能·trae
@yanyu66620 小时前
登录注册功能-明文
vue.js·springboot
滕青山1 天前
在线PDF拆分工具核心JS实现
前端·javascript·vue.js
光影少年1 天前
前端在页面渲染优化和组件优化经验?
前端·vue.js·react.js·前端框架
李白的天不白1 天前
VUE依赖配置问题
前端·javascript·vue.js
小智社群1 天前
获取贝壳新房列表
前端·javascript·vue.js
一 乐1 天前
茶叶商城|基于springboot + vue茶叶商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·茶叶商城系统