vue3 构建前端生成水印效果

vue3 实现前端生成水印效果

首先一点哈,就是单纯web前端生成水印只能作为警示使用,如果享彻底防住几乎是不可能的,有无数种方式去掉web前端生成的水印,所以这种方式只当是一个君子协议吧。

编写水印组件

首先直接把这部分封装成一个组件吧,我这边直接上代码了。

创建一个 waterMark.vue 文件,用来编写水印组件:

<template>
  <div class=
  "watermark-container" ref="parentRef">
  <slot>
    <
    /slot>
    <
    /div>
    <
    /template>
    <script setup>
      import { ref, onMounted, onUnmounted
      } from 'vue';
      import useWaterMarkBg from './waterMarkBg';
      const props = defineProps({
      text: {
      type: String,
      default: "版权所有"
      },
      fontSize: {
      type: Number,
      default: 25,
      },
      gap: {
      type: Number,
      default: 20,
      },
      color: {
      type: String,
      default: 'rgba(201, 35, 35, 0.5)'
      }
      })
      let div;
      const bg = useWaterMarkBg(props);
      const parentRef = ref();
      const ob = new MutationObserver((entries) =>
      {
      for (const entry of entries) {
      for (const node of entry.removedNodes) {
      if (node === div) {
      resetWatermark();
      return;
      }
      }
      if (entry.target === div) {
      resetWatermark();
      }
      }
      })
      onMounted(() =>
      {
      resetWatermark();
      ob.observe(parentRef.value, {
      childList: true,
      subtree: true,
      attributes: true,
      })
      })
      onUnmounted(() =>
      {
      ob.disconnect();
      })
      // 重置水印
      const resetWatermark = () =>
      {
      if (!parentRef.value) {
      return
      }
      if (div) {
      div.remove();
      }
      const { base64, size
      } = bg.value.value;
      div = document.createElement('div');
      div.style.position = 'absolute';
      div.style.backgroundImage = `url(${base64
      })`;
      div.style.backgroundSize = `${size.width
      }px ${size.height
      }px`;
      div.style.backgroundRepeat = "repeat";
      div.style.pointerEvents = 'none';
      div.style.zIndex = '9999';
      div.style.inset = 0;
      parentRef.value.appendChild(div);
      }
      <
      /script>
      <style scoped lang="scss">
        .watermark-container {
        position: relative;
        }
        <
        /style>

可以接受四个参数,如果不够可以自己加,分别是 text 水印文本内容fontSize 水印文本大小gap 水印文本间隔color 水印文本颜色

然后在水印组件加载完成的时候调用 resetWatermark 重置水印方法实现添加水印。

水印是动态生成的图片,最后创建了一个动态的div加上页面的,因为还想尽可能的防止一下水印删除,所以说在中途检测了一下dom修改情况,如果修改了,比如删除了div,或者是修改了div的样式,那么就重置水印,重新添加一遍。

其中在组件中还是用了 useWaterMarkBg 方法,下面代码是 waterMarkBg.js 文件的内容,可以根据自己的业务需求适当的修改:

import { ref, computed
} from 'vue';
/**
* 创建水印背景图片的 composable 函数
* @param {Object} options - 水印配置选项
* @param {string} options.text - 水印文字内容
* @param {number} options.fontSize - 字体大小
* @param {number} options.gap - 水印间隔
* @param {string} options.color - 文字颜色,默认为半透明灰色
* @param {number} options.rotate - 旋转角度,默认为 -15 度
* @param {string} options.fontFamily - 字体,默认为 Arial
* @returns {Object} 返回包含 base64 和 size 的响应式对象
*/
function useWaterMarkBg(options = {
}) {
// 默认参数
const defaultOptions = {
text: '版权所有',
fontSize: 25,
gap: 20,
color: 'rgba(201, 35, 35, 0.5)',
rotate: -15,
fontFamily: 'Arial, sans-serif'
};
// 合并用户参数和默认参数
const waterMarkOptions = ref({
...defaultOptions, ...options
});
// 计算水印尺寸和 base64 图片
const waterMarkInfo = computed(() =>
{
const { text, fontSize, gap, color, rotate, fontFamily
} = waterMarkOptions.value;
// 创建 canvas 元素
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
throw new Error('无法获取 canvas 上下文');
}
// 设置字体
ctx.font = `${fontSize
}px ${fontFamily
}`;
// 获取文字宽度
const textWidth = ctx.measureText(text).width;
// 计算 canvas 尺寸(包含文字和间隙)
const width = textWidth + gap * 2;
const height = fontSize * 2 + gap * 2;
canvas.width = width;
canvas.height = height;
// 重置上下文(因为 canvas 尺寸改变了)
ctx.font = `${fontSize
}px ${fontFamily
}`;
ctx.fillStyle = color;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// 保存当前状态
ctx.save();
// 移动到 canvas 中心并旋转
ctx.translate(width / 2, height / 2);
ctx.rotate((Math.PI / 180) * rotate);
// 绘制文字
ctx.fillText(text, 0, 0);
// 恢复之前的状态
ctx.restore();
// 转换为 base64
const base64 = canvas.toDataURL('image/png');
return {
base64,
size: {
width,
height
}
};
});
// 如果传入的 options 发生变化,可以更新水印
function updateOptions(newOptions) {
waterMarkOptions.value = {
...waterMarkOptions.value, ...newOptions
};
}
return {
value: waterMarkInfo,
updateOptions
};
}
export default useWaterMarkBg;

水印组件的使用

使用的时候就很简单了,引入一下,然后包裹一下需要添加水印的dom就可以了:

<
!-- 默认红色水印 -->
<water-mark text="严禁传播">
  <div class=
  "img-con">
  <img src="../../assets/imgs/watermark/1.jpg" alt="图片1">
    <
    /div>
    <
    /water-mark>
    <
    !-- 蓝色水印 -->
    <water-mark text="禁止复制" :fontSize="25" color="rgba(30, 144, 255, 0.3)">
      <div class=
      "img-con">
      <img src="../../assets/imgs/watermark/2.jpg" alt="图片2">
        <
        /div>
        <
        /water-mark>
        <
        !-- 绿色水印 -->
        <water-mark text="测试水印" :fontSize="25" color="rgba(50, 205, 50, 0.4)">
          <div class=
          "img-con">
          <img src="../../assets/imgs/watermark/1.jpg" alt="图片3">
            <
            /div>
            <
            /water-mark>

效果

在这里插入图片描述

好了,大体就这个样子,还是,水印这个很容易删除,懂得人,删的很快,最好从源头解决,只要后端返回前端的是原文件,那么就可以从浏览器获取到没有水印的内容。

posted @ 2025-09-16 21:57  yjbjingcha  阅读(8)  评论(0)    收藏  举报