foreword
Hello everyone, I'm Lin Sanxin, uses the most and easy-to-understand words to talk about the most difficult knowledge points. is my motto
background
Everyone usually encounters a problem during development or interview - to add watermark to the page, in fact, this is not difficult, but there are some points to pay attention to, so it is necessary to try to do the seemingly simple functions. arrive:
- 1. Rigorous
- 2. Security
implement watermark
In fact, it is not difficult to implement watermark, just use custom command + canvas + background-image, and it is very convenient to implement:
import type { Directive, App } from 'vue'
interface Value {
font?: string
textColor?: string
text?: string
}
const waterMarkId = 'waterMark'
const canvasId = 'can'
const drawWatermark = (el, value: Value) => {
const {
font = '16px Microsoft JhengHei',
textColor = 'rgba(180, 180, 180, 0.3)',
text = '三心大菜鸟',
} = value
// 创建一个canvas标签
const canvas = document.getElementById(canvasId) as HTMLCanvasElement
// 如果已有则不再创建
const can = canvas || document.createElement('canvas')
can.id = canvasId
el.appendChild(can)
// 设置宽高
can.width = 400
can.height = 200
// 不可见
can.style.display = 'none'
const ctx = can.getContext('2d')!
// 设置画布的样式
ctx.rotate((-20 * Math.PI) / 180)
ctx.font = font
ctx.fillStyle = textColor
ctx.textAlign = 'left'
ctx.textBaseline = 'middle'
ctx.fillText(text, can.width / 3, can.height / 2)
// 水印容器
const waterMaskDiv = document.createElement('div')
waterMaskDiv.id = waterMarkId
// 设置容器的属性样式
// 将刚刚生成的canvas内容转成图片,并赋值给容器的 background-image 样式
const styleStr = `
width: 100%;
height: 100%;
position: fixed;
z-index: -1;
top: 0;
left: 0;
pointer-events: none;
background-image: url(${can.toDataURL('image/png')})
`
waterMaskDiv.setAttribute('style', styleStr)
// 将水印容器放到目标元素下
el.appendChild(waterMaskDiv)
return styleStr
}
const watermarkDirective: Directive = {
mounted(el, { value }) {
// 接收styleStr,后面可以用来对比
el.waterMarkStylestr = drawWatermark(el, value)
}
}
When using, use v-watermark
directly:
<div
v-watermark="
{
text: '水印名称',
textColor: 'rgba(180, 180, 180, 0.3)'
}
"
>
The effect obtained is as follows:
Malicious modification
We have completed the watermark function, but let's think about it, what is the use of the watermark? Or why do we want to watermark a page? The answer is: Anti-counterfeiting
Yes, our watermarks are there to prevent counterfeiting, but does it really prevent counterfeiting like we just did? Let's recall our watermarking idea just now:
Step 1: Create a canvas and draw a watermark
Step 2: Create a watermark container div tag
Step 3: Convert the canvas to the image link and assign it to the background-image style attribute of the div tag
Step 4: Put the watermark container div under the target element
It seems to have completed the watermark function, but in fact is full of flaws ! ! ! for example:
- 1. Review the element to modify the background-image property of the container div to be empty
- 2. Inspect the element and delete the container div
If anyone with ulterior motives does both of these things, it will cause the watermark we just made on our page to disappear! ! !
So we have to monitor the malicious behavior of these people, so what should we do? MutationObserver
appeared! ! !
MutationObserver
For the specific usage of MutationObserver
, you can go to CDN
to see, here I will briefly talk about its function: Monitor the changes of DOM elements
Yes, what it does is: monitors changes in DOM elements , so he can prevent those malicious users from destroying the watermark, because as we just said, malicious users can use the following two methods to destroy the watermark:
- 1. Review the element to modify the background-image property of the container div to be empty
- 2. Inspect the element and delete the container div
Both of these points involve the modification of the DOM, so they will trigger the monitoring of MutationObserver
, so we can use MutationObserevr
to monitor. Here are two methods using its instance:
observe
: Enable monitoring of DOM changesdisconnect
: Stop monitoring DOM changes
const watermarkDirective: Directive = {
mounted(el, { value }) {
// 接收styleStr,后面可以用来对比
el.waterMarkStylestr = drawWatermark(el, value)
// 先定义一个MutationObserver
el.observer = new MutationObserver(() => {
const instance = document.getElementById(waterMarkId)
const style = instance?.getAttribute('style')
const { waterMarkStylestr } = el
// 修改样式 || 删除div
if ((instance && style !== waterMarkStylestr) || !instance) {
if (instance) {
// div还在,说明只是修改style
instance.setAttribute('style', waterMarkStylestr)
} else {
// div不在,说明删除了div
drawWatermark(el, value)
}
}
})
// 启动监控
el.observer.observe(document.body, {
childList: true,
attributes: true,
subtree: true,
})
},
unmounted(el) {
// 指定元素销毁时,记得停止监控
el.observer.disconnect()
el.observer = null
},
}
Now, if you modify style
or delete the container div, the watermark will be regenerated, so malicious users cannot succeed! ! ! Of course, there may be loopholes, we can give suggestions! !
Epilogue
I'm Lin Sanxin, an enthusiastic front-end rookie programmer. If you are motivated, like the front-end, and want to learn the front-end, then we can make friends and fish together haha, touch the fish group, add me, please note [Si No]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。