一、项目结构
二、项目代码
1.App.vue
<template>
<div class="container">
<Watermark text="版权所有">
<div class="content"></div>
</Watermark>
<Watermark text="禁止转载" style="background:#28c840">
<div class="content"></div>
</Watermark>
</div>
</template>
<script setup>
import Watermark from './components/WaterMark.vue'
</script>
<style scoped>
.container {
width: 100%;
/* height: 600px; */
display: flex;
justify-content: space-between
}
.content{
width:50vw;
height: 400px;
}
</style>
2.WaterMark.vue
<template>
<div class="watermark-container" ref="parent">
<slot></slot>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import useWatermarkBg from './useWatermarkBg'
const props = defineProps({
text: {
type: String,
required: true,
default: 'watermark'
},
fontSize: {
type: Number,
default: 20,
},
gap: {
type: Number,
default: 20,
}
})
const parent = ref()
let div
const bg = useWatermarkBg(props)
const ob = new MutationObserver((entries) => {
console.log("entries",entries);
for (const entry of entries) {
// console.log("entry",entry);
for (const node of entry.removedNodes) {
console.log("target", entry.target, "div", div);
if (node === div) {
resetWatermark()
console.log(123);
}
}
if (entry.target === div) {
resetWatermark()
console.log(456);
}
}
})
// 重置水印
function resetWatermark() {
if (!parent.value) {
return
}
if (div) {
div.remove()
}
const { base64, size } = bg.value
div = document.createElement('div')
div.style.position = 'absolute'
div.style.backgroundImage = `url(${base64})`
div.style.backgroundSize = `${size}px ${size}px`
div.style.backgroundRepeat = 'repeat'
div.style.zIndex = 9999
div.style.pointerEvents = 'none'
div.style.inset = 0
parent.value.appendChild(div)
}
onMounted(() => {
resetWatermark()
ob.observe(parent.value, {
childList: true,
subtree: true,
attributes: true,
})
})
onUnmounted(() => {
ob.disconnect()
})
</script>
<style scoped>
.watermark-container {
position: relative;
}
</style>
3.useWatermarkBg.js
import { computed } from "vue";
export default function useWatermarkBg(props) {
return computed(() => {
const canvas = document.createElement('canvas')
const devicePixelRatio = window.devicePixelRatio || 1
const fontSize = props.fontSize * devicePixelRatio
const font = fontSize + 'px serif'
const ctx = canvas.getContext('2d')
ctx.font = font
const { width } = ctx.measureText(props.text)
const canvasSize = Math.max(100, width) + props.gap * devicePixelRatio
canvas.width = canvasSize
canvas.height = canvasSize
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate((Math.PI / 180) * -45)
ctx.fillStyle = 'rgba(0,0,0,0.3)'
ctx.font = font
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText(props.text, 0, 0)
return {
base64: canvas.toDataURL(),
size: canvasSize / devicePixelRatio
}
})
}
三、运行效果