前端防篡改水印

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

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

相关推荐
战南诚3 小时前
VUE中,keep-alive组件与钩子函数的生命周期
前端·vue.js
霍理迪4 小时前
Vue的响应式和生命周期
前端·javascript·vue.js
SuperEugene9 小时前
Vue3 模板语法规范实战:v-if/v-for 不混用 + 表达式精简,避坑指南|Vue 组件与模板规范篇
开发语言·前端·javascript·vue.js·前端框架
Luna-player9 小时前
Vue 3 + Vue Router 的路由配置,简单示例
前端·javascript·vue.js
angerdream9 小时前
最新版vue3+TypeScript开发入门到实战教程之Vue3详解props
javascript·vue.js
~欲买桂花同载酒~10 小时前
项目优化-vite打包优化
前端·javascript·vue.js
踩着两条虫11 小时前
AI 驱动的 Vue3 应用开发平台 深入探究(二十):CLI与工具链之构建配置与Vite集成
前端·vue.js·ai编程
踩着两条虫11 小时前
AI 驱动的 Vue3 应用开发平台 深入探究(二十):CLI与工具链之自定义构建插件
前端·vue.js·ai编程
极梦网络无忧13 小时前
基于 Vite + Vue3 的组件自动注册功能
前端·javascript·vue.js
雪碧聊技术14 小时前
前端vue代码架子搭建
前端·javascript·vue.js·前端项目代码框架搭建