美文网首页
vue3 水印自定义指令

vue3 水印自定义指令

作者: 宏_4491 | 来源:发表于2024-01-14 10:59 被阅读0次

src/directive\watermark\index.ts


// 全局保存 canvas 和 div ,避免重复创建(单例模式)
const globalCanvas = null;
const globalWaterMark = null;

// 返回一个包含图片展示的 数据URL
const getDataUrl = (binding: any) => {
  const rotate = -20;
  const canvas = globalCanvas || document.createElement("canvas");
  const ctx:any = canvas.getContext("2d"); // 获取canvas画布的绘图环境

  ctx?.rotate((rotate * Math.PI) / 180); // 水印旋转角度
  ctx.font = binding.font;
  ctx.fillStyle = binding.fillStyle;
  ctx?.fillText(binding.text || '机密文件', canvas.width / 3, canvas.height / 1);

  return canvas.toDataURL("image/png");
};

// watermark 样式
let style = `
display: block;
overflow: hidden;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-repeat: repeat;
pointer-events: none;`;

// 定义指令配置项
const watermark: any = {
  mounted(el: HTMLElement, binding: any) {
    // 注意img有onload的方法,如果自定义指令注册在html标签的话,只需要init(el, binding.value)
    // el.onload = init.bind(null, el, binding);
    init(el, binding);
  },
};

// 初始化
const init = (el: HTMLElement, binding: any = {}) => {
  // 设置水印
  setWaterMark(el, binding.value);
  // 启动监控
  createObserver(el, binding.value);
};

// 设置水印
const setWaterMark = (el: HTMLElement, binding: any = {}) => {
  const { parentElement } = el;

  // 获取对应的 canvas 画布相关的 base64 url
  const url = getDataUrl(binding);

  // 创建 waterMark 父元素
  const waterMark = globalWaterMark || document.createElement("div");
  waterMark.className = `water-mark`; // 方便自定义展示结果
  style = `${style}background-image: url(${url});`;
  waterMark.setAttribute("style", style);

  // 将对应图片的父容器作为定位元素
  parentElement?.setAttribute("style", "position: relative;");

  // 将图片元素移动到 waterMark 中
  parentElement?.appendChild(waterMark);
};

/**
 * 监听 DOM 变化
 * 用 MutationObserver 对水印元素进行监听,删除时,我们再立即生成一个水印元素就可以了
 * @param el
 * @param binding
 */
const createObserver = (el: any, binding: any) => {
  const waterMarkEl = el.parentElement?.querySelector(".water-mark");
   
  const observer = new MutationObserver((mutationsList) => {
    console.log('mutationsList', mutationsList)
    if (mutationsList.length) {
      const { removedNodes, type, target } = mutationsList[0];
      const currStyle = waterMarkEl?.getAttribute("style");

      // 证明被删除了
      if (removedNodes[0] === waterMarkEl) {
        // 停止观察。调用该方法后,DOM 再发生变动,也不会触发观察器
        observer.disconnect();
        // 初始化(设置水印,启动监控)
        init(el, binding);
      } else if (
        type === "attributes" &&
        target === waterMarkEl &&
        currStyle !== style
      ) {
        waterMarkEl.setAttribute("style", style);
      }
    }
  });

  observer.observe(el.parentElement, {
    childList: true,
    attributes: true,
    subtree: true,
  });
};


watermark.install = (app: any) => {
    app.directive("watermark", watermark);
  };
  
  export default watermark;
  

main.ts

import watermark from "./directive/watermark/index";

app.use(watermark);

相关文章

网友评论

      本文标题:vue3 水印自定义指令

      本文链接:https://www.haomeiwen.com/subject/uzoqodtx.html