Kazaf's blog Kazaf's blog
首页
  • javascript
  • typescript
  • vue
  • react
  • babel
  • nginx
GitHub (opens new window)

Kazaf

前端打字员
首页
  • javascript
  • typescript
  • vue
  • react
  • babel
  • nginx
GitHub (opens new window)
  • JavaScript

  • Typescript

  • Vue

    • vue添加水印
      • WaterMark指令
      • 使用
  • react

  • 前端
  • Vue
Kazaf
2022-05-26

vue添加水印

# vue添加水印

# WaterMark指令

const watermark = {
  text: 'text',
  style: {},
  isAllowDele: false,
  maskDiv: '',
  init: (text) => {
    const canvas = document.createElement('canvas')
    canvas.id = 'canvas'
    canvas.width = watermark.style.width // 单个水印的宽高
    canvas.height = watermark.style.height
    watermark.maskDiv = document.createElement('div')
    const ctx = canvas.getContext('2d')
    ctx.font = watermark.style.font // 设置样式
    ctx.fillStyle = watermark.style.fillStyle // 水印字体颜色
    ctx.rotate(watermark.style.rotate) // 水印偏转角度
    // convas 设置换行
    CanvasRenderingContext2D.prototype.wrapText = function (
      text,
      x,
      y,
      maxWidth,
      lineHeight
    ) {
      if (
        typeof text != 'string' ||
        typeof x != 'number' ||
        typeof y != 'number'
      ) {
        return
      }
      const context = this
      const canvas = context.canvas
      if (typeof maxWidth == 'undefined') {
        maxWidth = (canvas && canvas.width) || watermark.style.width
      }
      if (typeof lineHeight == 'undefined') {
        lineHeight =
          (canvas && parseInt(window.getComputedStyle(canvas).lineHeight)) ||
          parseInt(window.getComputedStyle(document.body).lineHeight)
      }
      // 字符分隔为数组
      const arrText = text.split('')
      let line = ''
      for (var n = 0; n < arrText.length; n++) {
        let testLine = line + arrText[n]
        let metrics = context.measureText(testLine)
        let testWidth = metrics.width
        if (testWidth > maxWidth && n > 0) {
          context.fillText(line, x, y)
          line = arrText[n]
          y += lineHeight
        } else {
          line = testLine
        }
      }
      context.fillText(line, x, y)
    }
    ctx.wrapText(watermark.text, 30, 20)
    const src = canvas.toDataURL('image/png')
    watermark.maskDiv.style.position = 'fixed'
    watermark.maskDiv.style.zIndex = '9999'
    watermark.maskDiv.id = '_waterMark'
    watermark.maskDiv.style.top = '0'
    watermark.maskDiv.style.left = '0'
    watermark.maskDiv.style.height = '100%'
    watermark.maskDiv.style.width = '100%'
    watermark.maskDiv.style.pointerEvents = 'none'
    watermark.maskDiv.style.backgroundImage = 'URL(' + src + ')'
    // 水印节点插到body下
    document.body.appendChild(watermark.maskDiv)
  },
  // 防删机制
  monitor: () => {
    const body = document.getElementsByTagName('body')[0]
    const options = {
      childList: true,
      attributes: true,
      characterData: true,
      subtree: true,
      attributeOldValue: true,
      characterDataOldValue: true
    }
    const observer = new MutationObserver(watermark.callback)
    observer.observe(body, options) // 监听body节点
  },
  // DOM改变执行callback
  callback: (mutations, observer) => {
    // 当attribute属性被修改
    if (mutations[0].target.id === '_waterMark') {
      watermark.removeMaskDiv()
    }
    // 当id被改变时
    if (mutations[0].attributeName === 'id') {
      watermark.removeMaskDiv()
      watermark.init()
    }
    // 当节点被删除
    if (
      mutations[0].removedNodes[0] &&
      mutations[0].removedNodes[0].id === '_waterMark'
    ) {
      watermark.init()
    }
  },
  // 手动销毁水印DOM
  removeMaskDiv: () => {
    document.body.removeChild(watermark.maskDiv)
  },
  render: () => {
    // let maskBox = document.querySelector('#_waterMark');
    if (!watermark.maskDiv) {
      watermark.init()
      // 是否允许通过js或开发者工具等途径修改水印DOM节点(水印的id,attribute属性,节点的删除),true为允许, 默认不允许
      if (!watermark.isAllowDele) {
        // 设置水印节点修改的DOM事件
        watermark.monitor()
      }
    }
  }
}

export default {
  bind(el, binding, vnode) {
    const options = binding.value
    watermark.style = options.style
    watermark.text = options.text
    watermark.isAllowDele = options.isAllowDele
    watermark.render()
  },
  update(element, data) {
    if (data.value.text !== data.oldValue.text) {
      watermark.text = data.value.text
      watermark.removeMaskDiv()
      watermark.render()
    }
  }
}
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

# 使用

<template>
    <router-view v-waterMark="waterCode"></router-view>
</template>

<script>
import waterMark from 'common/utils/watermark'
export default {
  directives: {
    waterMark
  },
  computed: {
    waterCode() {
      return {text: `平台机密数据`,
        style: {
          'width': 700, // 单个水印的宽
          'height': 300, // 单个水印的高
          'font': 'normal 22px Microsoft Yahei', // 设置样式
          'fillStyle': 'rgba(112, 113, 114, 0.1)', // 水印字体颜色
          'rotate': (30 * Math.PI / 180) // 水印偏转角度
        }
      }
    }
  }
}
</script>
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
编辑 (opens new window)
#Vue
上次更新: 2022/05/26, 11:38:11
Ts高级类型-UtilityTypes
React中的受控和非受控组件

← Ts高级类型-UtilityTypes React中的受控和非受控组件→

最近更新
01
React中的受控和非受控组件
09-22
02
nginx基本配置
06-01
03
工具方法收集
05-20
更多文章>
Theme by Vdoing | Copyright © 2021-2022
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式