loading

v-watermark自定义指令

# 自定义指令v-watermark

# 封装

const globalCanvas = null;
const globalWaterMark = null;

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

const getDataUrl = ({
  font,
  fillStyle,
  textAlign,
  textBaseline,
  text,
  rotate = -20,
}) => {
  font = font || "16px normal";
  fillStyle = fillStyle || "rgba(180, 180, 180, 0.2)";
  text = text || "";
  const canvas = globalCanvas || document.createElement("canvas");
  const ctx = canvas.getContext("2d"); // 获取画布上下文
  ctx.rotate((rotate * Math.PI) / 180);
  ctx.font = font;
  ctx.fillStyle = fillStyle;
  ctx.textAlign = textAlign || "left";
  ctx.textBaseline = textBaseline || "middle";
  ctx.fillText(text, canvas.width / 10, canvas.height / 2);

  return canvas.toDataURL("image/png", 1); // 第二个参数为质量
};

const setWaterMark = (el, binding) => {
  const parentElement = el.parentElement;

  // 获取对应的 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 变化
const createObserver = (el, binding) => {
  const waterMarkEl = el.parentElement.querySelector(".water-mark");

  const observer = new MutationObserver((mutationsList) => {
    if (mutationsList.length) {
      const { removedNodes, type, target } = mutationsList[0];
      const currStyle = waterMarkEl?.getAttribute("style");
      // 证明被删除了
      if (removedNodes[0] === waterMarkEl) {
        observer.disconnect();
        // 重新添加水印,dom监听
        init(el, { value: binding });
      } else if (
        type === "attributes" &&
        target === waterMarkEl &&
        currStyle !== style
      ) {
        waterMarkEl.setAttribute("style", style);
      }
    }
  });

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

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

// 定义指令配置项
const directives = {
  inserted(el, binding) {
    init(el, binding);
  },
};

export default {
  name: "watermark",
  directives,
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

# 使用

# 1、引入

main.js
import waterMark from './directives/waterMark.js'
Vue.directive('watermark', waterMark.directives)
1
2
3

# 2、使用

<div id="app" v-watermark="{ text: '绝密资料,请勿外传' }">
  <router-view />
</div>
1
2
3
// 禁止打开控制台
const prohibitOpenConsole = () => {
    // 阻止f12调试、window ctr + shift + i 、 mac option +  command + i
    document.addEventListener('keydown', (e) => {
      if (e.key === 'F12' || (e.ctrlKey && e.shiftKey && e.key === 'i') || (e.metaKey && e.altKey && e.key === 'i')) {
        e.preventDefault()
        // IE
        e.returnValue = false
      }
    })

    // 阻止菜单右键
    document.addEventListener('contextmenu', (e) => {
      e.preventDefault()
      e.returnValue = false
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
最近更新时间: 2023/07/17 13:56:35
最近更新
01
2023/07/17 13:57:35
02
2023/07/17 09:24:52
03
2023/07/14 16:02:42