“我正在参加「掘金·启航计划」”
1、思路
1.1、如何生成水印
- 在需要加水印的区域,加
div元素,且让该div元素填充满该区域,再给这个div元素一个背景图,并让这个背景图重复铺满需要水印的区域。而这个背景图可使用canvas来绘制,绘制一个透明、可以根据传入的字体大小、间隔大小绘制的图片
1.2、如何防止篡改
- 这里需要
MutationObserver与watchEffect结合使用MutationObserver:提供了监视对DOM树所做更改的能力,在DOM被修改时,修改watchEffect收集的依赖项watchEffect:依赖项被修改时,再次执行- MutationObserver可点击查看其用法
2、实现
2.1、实现一个水印组件
- 在这个水印组件中,可以接受三个值:
text、fontSize、gap,除此之外,也可以根据实际需求添加所需要的值text:是水印文字fontSize:是水印文字的字体大小gap:是生成的水印图片间隔大小
const props = defineProps({
text: {
type: String,
required: true,
default: 'WaterMark'
},
fontSize: {
type: Number,
default: 40
},
// 间隙
gap: {
type: Number,
default: 20
}
})
- 在这个组件中,我们并不能直接在
template中直接添加div元素,因为:在template中直接添加div元素,被删除后,不可以被重新生成,所以我们要用ts去创建div元素,也不能在class中直接添加样式,道理也同上,需要使用ts来添加样式 - 因为需要让水印铺满,所以可以使用
inset属性,设置为0,则四边到父元素的距离都为0
const bg = useWatermarkBg(props)
const parentRef: any = ref(null)
let div: any
watchEffect(() => {
if (!parentRef.value) {
return
}
// 如果节点有值,进行删除
if (div) {
div.remove()
}
const { base64, styleSize } = bg.value
div = document.createElement('div')
div.style.backgroundImage = `url(${base64})`
div.style.backgroundSize = `${styleSize} px ${styleSize}px`
div.style.backgroundRepeat = 'repeat'
div.style.zIndex = '9999'
div.style.position = 'absolute'
div.style.inset = '0'
div.style.pointerEvents = 'none'
parentRef.value.appendChild(div)
})
- 上述代码中使用到一个生成
canvas的hook函数useWatermarkBg,这个函数,返回了base64、size、styleSize三个值 base64就是水印图片地址,若为了水印图更加清晰,我们选择使用styleSize,而为什么使用styleSize,有空在下一篇讲解,本篇就不做更多介绍canvas了useWatermarkBg将在最后和全部代码一起给出- 这时已经可以生成水印,但是仍然可以被删掉水印,如下图
2.2、实现防止篡改水印(删除)
- 防止篡改有两步:
- 1、使用
MutationObserver进行监控元素的变化(本身和监控元素里的所有子元素) - 2、使用
watchEffect重新生成
- 1、使用
- 在这里就需要使用上文提到的
MutationObserver了,我们需要创建监听器new MutationObserver():observer = new MutationObserver() new好之后,我们会使用到以下两个方法observe:监听器,接收两个参数。1是传入监听的节点,2是相关配置,比如:
observer.observe(parentRef.value, { // 元素内容 childList: true, // 本身属性 attributes: true, // 整个子树 subtree: true })disconnect:停止监听,在DOM卸载时,便要停止监听
onUnmounted(() => { observer && observer.disconnect() // 取消监听 })- 我们试着去删除水印,看看是否可以监听到这个操作
-
可以看到的是,我们删除水印,触发了监听:
removedNodes: [div] -
我们试着去修改样式,看看是否可以监听到这个操作
-
可以看到的是,我们修改了水印样式,触发了监听:
attributename: "style" -
那为什么在
gif图中水印并没有被删除成功以及水印样式没有被修改成功呢?其实,水印已经被删除过一次以及样式已经被修改过了。 -
而再次出现是因为,在我的代码中已将
MutationObserver与watchEffect结合使用了,且在监听到删除操作或者修改操作时,将watchEffect的依赖项(flag.value++)进行修改,watchEffect监听到依赖项的改变,包含的方法就会再次执行,这样水印就会重新出现
let observer: any
onMounted(() => {
// 创建监听器
observer = new MutationObserver((records) => {
console.log(records)
for (const record of records) {
// 删除水印
for (const dom of record.removedNodes) {
if (dom === div) {
// 有删除操作
console.log('删除了水印')
flag.value++
return
}
}
// 监控修改
if (record.target === div) {
console.log('修改了水印样式')
flag.value++
return
}
}
})
// 监听谁--父元素
observer.observe(parentRef.value, {
// 监听配置:监听什么
// 元素内容
childList: true,
// 本身属性
attributes: true,
// 整个子树
subtree: true
})
})
- 水印效果如图:
- 左边一张图片,右边一段文字,也可以给视频添加水印
- 需要代码可访问github获取