基于Vue3+Ts实现水印方法封装

基于Vue3+Ts实现水印方法封装

昨天在看公司源码的时候看到一个 utils 文件夹里封装了一个 waterMark.js,是实现添加水印功能的,研究了一下,是通过 canvas 画布画出水印然后再转换成图片最后再作为页面元素的背景,并且里面会返回一个唯一的标识符 id 来防止用户篡改,在项目中的应用具体是通过 sessionStorage.getItem() 来获取用户名然后再在后面添加一段当前的时间。

公司项目的水印功能是通过 Vue2 实现的,而我觉得这个水印功能具体还能继续优化一下,因为刚学 Ts 不久,我就想着用 Vue3 + Ts 尝试着重新封装一下,刚好在掘金上看到有一位博主写的:vue3 项目添加水印的实现方法 – 掘金 (juejin.cn) ,是通过 Vue3 + Ts 封装实现的,二者都是同样的思路,所以我就在这位博主代码的基础上进一步做了封装优化。

具体优化

  1. 对于水印的添加,可以选择在水印内容下方添加水印的生成时间,具体如图所示:

基于Vue3+Ts实现水印方法封装

基于Vue3+Ts实现水印方法封装

  1. 实现两种添加水印的方式,一种为全屏添加,一种为指定容器添加,会根据传入的参数进行判断:

基于Vue3+Ts实现水印方法封装

基于Vue3+Ts实现水印方法封装

  1. 原来添加水印的容器会被监听,当容器大小变化时会重新调用设置水印方法实现水印的自适应,在此基础上加了:当组件销毁时,移除所有事件的监听。

代码实现

因为要实现全屏和局部容器添加水印两种方式,而局部容器无法通过 onresize 方法实现监听,在这里就统一采用 new ResizeObserver() 这个 API 来实现元素大小的监听,具体使用方法可以这篇文章:监测DOM元素尺寸大小变化|Vue – 掘金 (juejin.cn)

import { onBeforeUnmount } from "vue";
​
export const getMark = () => {
 /**
    * 设置水印方法
    * @param {string} str - 输出文本
    * @param {HTMLElement} [container] - 设置水印的容器(如果不写则默认设置全屏水印)
    * @param {boolean} [createTime] - 水印生成时间
    */
 const setWaterMark = (str: string, createTime: boolean, container?: HTMLElement) => {
   // 创建唯一标识符id
   const id = "1.23452384164.123412416";
   if (document.getElementById(id) !== null) {
     container ? container.removeChild(document.getElementById(id)!) : document.body.removeChild(document.getElementById(id)!);
   }
   // 创建画布
   const can = document.createElement("canvas");
   // 设置画布长宽
   can.width = 150;
   can.height = 120;
   // 获取画布元素2D渲染上下文
   const cans = can.getContext("2d")!;
   // 设置旋转角度(逆时针旋转15度)
   cans.rotate((-15 * Math.PI) / 180);
   // 设置字体
   cans.font = "18px Vedana";
   // 设置填充绘色
   cans.fillStyle = "rgba(200, 200, 200, 0.40)";
   // 设置在绘制文本时使用当前文本基线
   cans.textBaseline = "middle";
   /**
    * 在画布上绘制填色文本
    * @param {string} str - 输出文本
    * @param {number} width - 开始绘制文本X坐标位置
    * @param {number} height - 开始绘制文本Y坐标位置
    */
   cans.fillText(str, can.width / 8, can.height / 2);
​
   if (createTime) {
     // 获取当前时间并格式化
     let curDate = new Date();
     let dateStr = curDate.toLocaleDateString();
     let timeStr = curDate.toLocaleTimeString();
     let timeStamp = `${dateStr} ${timeStr}`;
     const timeTextWidth = cans.measureText(timeStamp).width;
     const timeTextX = (can.width - timeTextWidth) / 2;
     cans.font = "14px Vedana";
     cans.fillText(timeStamp, timeTextX, (can.height / 3) * 2);
   }
   // 创建全屏浮动全屏浮动div, 将画布作为背景
   const div = document.createElement("div");
   div.id = id;
   div.style.pointerEvents = "none";
   div.style.top = "20px";
   div.style.left = "0px";
   div.style.position = "absolute";
   div.style.zIndex = "999999";
   div.style.width = container ? container.clientWidth + "px" : "100%";
   div.style.height = container ? container.clientHeight + "px" : "100%";
   div.style.background =
     "url(" + can.toDataURL("image/png") + ") left top repeat";
   if (container) {
     container.style.position = "relative";
     container.appendChild(div);
   } else {
     document.body.appendChild(div);
   }
​
   return id;
};
​
 // 只允许调用一次该方法
 const waterMark = (str: string, createTime: boolean, container?: HTMLElement) => {
   let id = setWaterMark(str, createTime, container);
   // 定时检查是否存在具有相同标识符的元素
   setInterval(() => {
     if (document.getElementById(id) === null) {
       id = setWaterMark(str, createTime, container);
     }
   }, 500);
​
   // 监听窗口大小调整, 确保水印的适应性
   const handleResize = () => {
     setWaterMark(str, createTime, container);
   };
   const observer = new ResizeObserver(handleResize);
   // 全屏监听
   if (!container) {
     observer.observe(document.documentElement, { box: "content-box" });
   }
   // 指定容器监听
   else {
     observer.observe(container, { box: "content-box" });
   }
​
   // 组件销毁时清除监听
   onBeforeUnmount(() => {
     observer.disconnect();
   });
};
 return { waterMark }
};

具体应用

在组件中直接引入 waterMark.ts 解构出相应的方法进行使用即可,其中 waterMark() 方法的参数情况如下表:

方法名 waterMark
参数 str: string – 水印文本 createTime: boolean – 是否添加水印生成时间 container?: HTMLElement – 水印容器(可选,默认为整个页面)
返回值
功能 创建水印,并根据需要定时检查是否存在具有相同标识符的元素。监听窗口大小调整,以确保水印的适应性,并在组件销毁时清除监听。
注意事项 str参数为水印文本,可以是任意字符串。 – createTime参数用于控制是否添加水印生成时间。 – container参数是一个可选的参数,用于指定水印的容器,默认为整个页面。如果提供了容器,水印将被添加到指定容器中。如果未提供容器,水印将添加到整个页面中。 – 组件销毁时会自动清除监听,无需手动清除。

实际应用例子如下:

<template>
 <div class="box" ref="boxRef"></div>
</template>
​
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { getMark } from "../utils/waterMark";
const boxRef = ref(null); 
const { waterMark } = getMark();
onMounted(() => {
 waterMark("PandaGuo", false, boxRef.value!); //添加水印
});
</script>
<style scoped>
.box {
 width: 500px;
 height: 500px;
 background-color: black;
}
</style>

基于Vue3+Ts实现水印方法封装

源码地址

[github.com/Panda-Gu0/W…]  github源码地址

原文链接:https://juejin.cn/post/7262279674594836540 作者:迪士尼在逃保安

(0)
上一篇 2023年8月2日 上午11:07
下一篇 2023年8月3日 上午10:00

相关推荐

发表回复

登录后才能评论