基于Vue3水印组件封装:防篡改守护!

vue3 · 浏览次数 : 0

小编点评

**Watermark Component in Vue 3** This Vue 3 component provides a simple and efficient way to add custom watermarks to your web or application. It boasts the following features: * **Fully functional:** Supports various props for watermark configuration. * **Easy integration:** Simply import the component and use the provided props to configure the watermark. * **Efficient rendering:** Uses a computed property to generate the watermark on demand. * **Multiple customization options:** Allows you to control color, size, and positioning of the watermark. **Usage:** 1. Import the component into your Vue project. 2. Define the necessary props for the watermark using the `defineProps` function. 3. Render the component in your template. **Example:** ```html ``` **Result:** This code will render a watermark with the text "张苹果博客" centered and sized to 10px. **Additional Notes:** * The `Watermark` component uses relative positioning to ensure it appears on top of other elements. * The `v-motion-pop-visible-once` directive allows you to animate the watermark's visibility. * You can customize the component's appearance by adjusting the props defined in the `defineProps` function.

正文

基于Vue 3的全新水印通用组件。这款组件不仅功能强大,而且易于集成,能够轻松为您的网页或应用添加自定义水印,有效防止内容被篡改或盗用。

在线查看效果: 原文可查看效果地址

一,编写watermark组件

<template>
   <div ref="watermarkContainerRef" class="watermark-container">
      <!--  插槽-->
     <slot></slot>
   </div>
</template>

<script setup>
import { ref, onMounted, watchEffect, onUnmounted, computed } from "vue";
// 使用 defineProps 定义一个组件的 props,这些 props 描述了组件从父组件接收的属性
const props = defineProps({
  // 文本内容,类型为字符串,必须提供,默认值为'张苹果博客'
  text: {
    type: String,
    required: true,
    default: '张苹果博客'
  },
  // 字体大小,类型为数字,默认值为10
  fontSize: {
    type: Number,
    default: 10,
  },
  // 间距,类型为数字,默认值为1
  gap: {
    type: Number,
    default: 1,
  },
  // 颜色,类型为字符串,默认值为'rgba(82,75,75,0.58)'
  color: {
    type: String,
    default: 'rgba(82,75,75,0.58)',
  }
});

// 定义一个用于绘制水印的函数,这里可以封装一下单独引入。
// 它是一个计算属性,意味着它的值会根据其依赖的 props 的变化而自动重新计算
const waterMarkBg = (props) => {
  return computed(() => {
    // 创建一个新的 canvas 元素
    const canvas = document.createElement("canvas");
    // 获取设备的像素比,如果未定义则默认为1
    const devicePixelRatio = window.devicePixelRatio || 1;
    // 根据像素比计算字体大小
    const fontSize = props.fontSize * devicePixelRatio;
    // 设置字体样式
    const font = fontSize + "px serif";
    // 获取 canvas 的 2D 渲染上下文
    const ctx = canvas.getContext("2d");
    // 设置字体
    ctx.font = font;
    // 测量文本的宽度
    const { width } = ctx.measureText(props.text);
    // 计算 canvas 的大小,至少为 60,并根据文本宽度和间距因子进行调整
    const canvasSize = Math.max(60, width) * props.gap + devicePixelRatio;
    // 设置 canvas 的宽高
    canvas.width = canvasSize;
    canvas.height = canvasSize;
    // 将 canvas 的原点移动到中心
    ctx.translate(canvas.width / 2, canvas.height / 2);
    // 旋转 canvas 45 度
    ctx.rotate((Math.PI / 180) * -45);
    // 设置填充颜色
    ctx.fillStyle = props.color;
    // 设置文本对齐方式和基线
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    // 再次设置字体
    ctx.font = font;

    // 在 canvas 上填充文本
    ctx.fillText(props.text, 0, 0);

    // 返回一个对象,包含 base64 编码的图片数据、canvas 的大小和样式尺寸
    return {
      base64: canvas.toDataURL(),
      size: canvasSize,
      styleSize: canvasSize / devicePixelRatio
    };
  });
};

// 用于存储 MutationObserver 的变量
let ob;
// 用于存储水印 div 的变量
let div;
// 调用 waterMarkBg 函数获取水印相关的计算属性
const bg = waterMarkBg(props);
// 创建一个 ref 用于存储水印容器的 DOM 引用
const watermarkContainerRef = ref('');
// 创建一个 ref 用于标记水印是否需要重新生成
const flag = ref(0);

// 在组件挂载后执行
onMounted(() => {
  // 创建一个新的 MutationObserver,用于监听水印容器的变化
  ob = new MutationObserver((records) => {
    // 遍历所有的变化记录
    for (const record of records) {
      // 遍历所有被移除的节点
      for (const dom of record.removedNodes) {
        // 如果被移除的节点是水印 div,则更新 flag 的值并返回
        if (dom === div) {
          flag.value++;
          return;
        }
      }
      // 如果变化的节点就是水印 div,则更新 flag 的值并返回
      if (record.target === div) {
        flag.value++;
        return;
      }
    }
  });
  // 包括子节点的变化、属性的变化以及子树的变化
  ob.observe(watermarkContainerRef.value,{
    childList:true,
    attributes:true,
    subtree:true
  });
})

//卸载
onUnmounted(()=>{
  ob && ob.disconnect();
  div=null;
})

// 生成水印
watchEffect(() => {
  // 触发 watchEffect 的重新执行
  flag.value;
  // 如果水印容器没有值,则直接返回,不执行后续操作
  if (!watermarkContainerRef.value) {
    return;
  }
  // 如果之前已经存在水印 div,则先移除它
  if (div) {
    div.remove();
  }
  // 创建一个新的 div 元素用于作为水印的容器
  div = document.createElement('div');
  // 从计算属性 bg 中获取 base64 编码的图片数据和样式尺寸
  const { base64, styleSize } = bg.value;
  // 设置 div 的背景图片为水印图片的 base64 编码
  div.style.backgroundImage = `url(${base64})`;
  // 设置背景图片的尺寸
  div.style.backgroundSize = `${styleSize}px ${styleSize}px`;
  // 设置背景图片重复显示
  div.style.backgroundRepeat = "repeat";
  // 设置水印 div 的 z-index 为 9999,以确保它显示在大多数其他元素之上
  div.style.zIndex = 9999;
  // 设置水印 div 不响应鼠标事件,如点击、悬停等
  div.style.pointerEvents = "none";
  // 设置水印 div 的位置为绝对定位
  div.style.position = "absolute";
  // 使用 inset 属性设置 div 占据整个父容器的空间
  div.style.inset = "0";
  // 将水印 div 添加到水印容器中
  watermarkContainerRef.value.appendChild(div);
});


</script>

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

</style>

二,在页面中引入使用

<template>
 <div>
   <n-grid>
     <n-gi style="margin: 15px"   span="6 1025:2  "  v-for="(item,index) in 4" :key="index">
<!--       引入 Watermark-->
         <Watermark :gap="gap" :text="text" :fontSize="fontSize" :color="color">
           <n-card
               v-motion-pop-visible-once
              title="标题"
               hoverable
           >
            这是内容 <br>
            这是内容 <br>
            这是内容 <br>
            这是内容 <br>
            这是内容 <br>
            这是内容 <br>
           </n-card>
         </Watermark>

     </n-gi>
   </n-grid>

 </div>
</template>

<script setup>
import Watermark from '../components/Watermark.vue'
import {ref} from "vue";
const text=ref('张苹果博客');
const gap=ref(1);
const fontSize=ref('10');
const color=ref('');
</script>

<style scoped>

</style>

三,效果图

水印效果图

更多信息请访问:张苹果博客

与基于Vue3水印组件封装:防篡改守护!相似的内容:

基于Vue3水印组件封装:防篡改守护!

基于Vue 3的全新水印通用组件封装。这款组件不仅功能强大,而且易于集成,能够轻松为您在网页任何位置添加自定义水印,有效防止内容被篡改或盗用。

Vite-Wechat网页聊天室|vite5.x+vue3+pinia+element-plus仿微信客户端

基于Vue3+Pinia+ElementPlus仿微信网页聊天模板Vite5-Vue3-Wechat。 vite-wechat使用最新前端技术vite5+vue3+vue-router@4+pinia+element-plus搭建网页端仿微信界面聊天系统。包含了聊天、通讯录、朋友圈、短视频、我的等功

基于SqlSugar的开发框架循序渐进介绍(29)-- 快速构建系统参数管理界面-Vue3+ElementPlus

在随笔《基于SqlSugar的开发框架循序渐进介绍(28)-- 快速构建系统参数管理界面》中介绍了基于SqlSugar开发框架,构建系统参数管理的后端API部分,以及WInform界面部分内容,本篇随笔介绍基于Vue3+ElementPlus的前端界面开发过程。

这个vue3的后台管理系统虽然简洁但不简单

今天介绍一个新的Vue后台管理框架,相比其他后台功能丰富管理系统,这个后台管理系统可以用干净简洁来形容——Nova-admin Nova-admin Nova-admin 是一个基于Vue3、Vite5等最新技术的后台管理平台。用简单的方式实现完整功能,并尽可能的考虑代码规范,易读易理解无过度封装,

基于SqlSugar的开发框架循序渐进介绍(19)-- 基于UniApp+Vue的移动前端的功能介绍

在之前的SqlSugar系列随笔中,介绍了很多我们关于SqlSugar的开发框架的内容,SqlSugar的开发框架的目的是多前端应用场景,因此其中会包含各种不同的前端应用,前面介绍了基于DevExpress的Winform的前端应用,以及基于Vue3+TypeScript+ElementPlus的BS前端应用,本篇随笔继续介绍SqlSugar的开发框架的另一个前端应用,基于UniApp+Vue+T

基于SqlSugar的开发框架循序渐进介绍(25)-- 基于SignalR实现多端的消息通讯

基于ASP.NET Core SignalR 可以实现客户端和服务器之间进行即时通信。本篇随笔介绍一些SignalR的基础知识,以及结合对SqlSugar的开发框架的支持,实现SignalR的多端处理整合,从而实现Winform客户端,基于Vue3+ElementPlus的BS端整合,后面也可以实现对移动端的SignalR的整合通讯。

02.前后端分离中台框架前端 admin.ui.plus 学习-介绍与简单使用

## 中台框架前台项目 admin.ui.plus 的初识 > 基于 vue3.x + CompositionAPI setup 语法糖 + typescript + vite + element plus + vue-router-next + pinia 技术,内置支持一键生成微服务接口,适配手

基于uniapp+vue3自定义增强版table表格组件「兼容H5+小程序+App端」

vue3+uniapp多端自定义table组件|uniapp加强版综合表格组件 uv3-table:一款基于uniapp+vue3跨端自定义手机端增强版表格组件。支持固定表头/列、边框、斑马纹、单选/多选,自定义表头/表体插槽、左右固定列阴影高亮显示。支持编译兼容H5+小程序端+App端。 如下图:

推荐一套轻量级的开源图床系统:Light Fast Picture

如果您跟我一样平时有些博客的习惯,那么图片存储是否有困扰过你呢?今天就给大家推荐一款不错的开源图床系统:Light Fast Picture 它是一个基于koa + vue3.x + typescript实现的图床工具。它可以帮助用户快速上传图片到云端,并返回图片链接,方便用户在网页、社交媒体等平台

uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈

原创研发uniapp+vue3+pinia2跨三端仿微信app聊天模板Uniapp-Wechat。 uni-vue3-wchat基于uni-app+vue3+pinia2+uni-ui+uv-ui等技术跨端仿制微信App界面聊天项目,支持编译到H5+小程序端+App端。实现编辑框多行消息/emoj混