前端防篡改水印

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

环境 :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...

相关推荐
这里是杨杨吖2 小时前
SpringBoot+Vue医院预约挂号系统 附带详细运行指导视频
vue.js·spring boot·医院·预约挂号
光影少年4 小时前
vue打包优化方案都有哪些?
前端·javascript·vue.js
木易 士心7 小时前
Ref 和 Reactive 响应式原理剖析与代码实现
前端·javascript·vue.js
被巨款砸中7 小时前
一篇文章讲清Prompt、Agent、MCP、Function Calling
前端·vue.js·人工智能·web
rggrgerj10 小时前
Vue3 组件完全指南代码
前端·javascript·vue.js
在逃的吗喽11 小时前
Vue3新变化
前端·javascript·vue.js
Demoncode_y12 小时前
Vue3中基于路由的动态递归菜单组件实现
前端·javascript·vue.js·学习·递归·菜单组件
茶憶13 小时前
uniapp 请求接口封装和使用
vue.js·uni-app
岁月宁静13 小时前
🎨 打造 AI 应用的 “门面”:Vue3.5 + MarkdownIt 实现高颜值、高性能的答案美化组件
前端·javascript·vue.js
码农飞哥13 小时前
AI编程开发系统001-基于SpringBoot+Vue的旅游民宿租赁系统
vue.js·spring boot·毕业设计·ai编程·计算机源码