首页 > 其他分享 >Vue3水印组件

Vue3水印组件

时间:2024-08-09 15:56:06浏览次数:10  
标签:canvas const props 水印 Vue3 组件 div ref

1、组件封装

<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>

2、引用

<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">
           内容展示。。。
         </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>

标签:canvas,const,props,水印,Vue3,组件,div,ref
From: https://www.cnblogs.com/axingya/p/18350885

相关文章

  • Vue3入门项目 简洁清晰保姆级内容讲解
    序章vue3的后台管理项目,从0到1搭建,内容非常丰富涵盖项目搭建、路由配置、用户鉴权、首页报表、用户列表、前后端联调等功能,推荐指数:5颗星!视频学习链接:vue3通用后台管理-零基础从0到1详细的入门保姆级别教程——哔哩哔哩bilibili环境配置node版本:需要Node.js版本1......
  • Vue3拖拽功能 vue-draggable-plus
    Vue拖拽功能vue-draggable-plus,支持V2和V3文章目录Vue拖拽功能vue-draggable-plus,支持V2和V3介绍VueDraggablePlus一、使用说明版本支持安装二、使用实例1.双列表拖拽2.更多拖拽效果总结介绍VueDraggablePlus最近需要pc上做拖拽功能,之前在移动端使用的是Sor......
  • OpenTiny HUICharts开源发布,带你了解一个简单、易上手的图表组件库
    摘要:目前OpenTinyHUICharts已经成功落地在华为内部100多个产品中,持续提升了用户的可视化体验。本文分享自华为云社区《OpenTinyHUICharts正式开源发布,一个简单、易上手的图表组件库》,作者:OpenTiny。引言大家好!我们非常高兴地跟大家宣布,今天正式发布我们的新产品——Open......
  • 使用 defineNuxtComponent`定义 Vue 组件
    title:使用defineNuxtComponent`定义Vue组件date:2024/8/9updated:2024/8/9author:cmdragonexcerpt:摘要:本文介绍了在Nuxt3中使用defineNuxtComponent辅助函数定义类型安全的Vue组件的方法,适用于习惯OptionsAPI的开发者。defineNuxtComponent支持asyncData获取异......
  • EasyPlayer.js在使用vue3中使用
    npminstall@easydarwin/easyplayer--save把node_modules/@easydarwin/easyplayer/dist/element目录下的文件 复制到public内index.html<scripttype="text/javascript"src="/js/EasyPlayer-element.min.js"></script>在使用的vue内直接写<templ......
  • 一个升级的多租户权限管理系统,组件化,模块化,轻耦合,高扩展企业级的应用框架,功能强大(
    前言在现代软件开发中,多租户权限管理系统是企业级应用中的一个关键组件。然而,现有的一些框架,如RuoYi,虽然提供了一些基本的功能,但在面对更复杂的企业级需求时,如原生的MyBatis使用、复杂的分页处理,以及一些高级功能支持上,仍然存在一些不足和痛点。为了解决这些问题,并提供一个更......
  • element--tree树形组件
    一、有一个default-expand-all是否默认展开所有节点的属性,只在第一次初始化tree的时候有效,改变这个属性的值好像不能控制展开折叠给出示例代码:<template><div><el-tree:data="treeData"ref="tree":default-expand-all="false"></el-tree><el-button@clic......
  • DzzOffice 新闻插件查看页面添加水印
    文件:\dzz\news\template\news_view.htm这里以显示用户名水印为示例<scripttype="text/javascript">//需要用到的地方调用就好watermark({watermark_txt:'$_G[username]'})functionwatermark(settings){//默认设置vardefaultSettings={......
  • vue3(nuxt3)+Aliplayer播放器进行直播播流
    前言:    上一篇讲到使用自定义的一个播放器去进行播流进行观看直播,由于之前都是自己研发的,服务器不是特别好,所以决定使用阿里的推流以及阿里的播放器去进行拉流也更加的适配吧,至少后面出现问题可以有文档看比较完善实践    1.这里的话先把官方文档的地......
  • 一个基于 vue 的强大表单和高性能表格组件,简洁API设计,支持虚拟树,列拖拽,懒加载,快捷
    前言在现代Web应用开发中,表单和表格是两个核心组件,它们对于数据展示和用户交互至关重要。然而,现有的解-决方案往往存在一些痛点,如不够灵活、性能问题、以及难以实现复杂功能等。这些问题限制了开发者的创造力,也影响了用户体验。为了解决这些痛点,开发者需要一款功能强大、灵活......