Appearance
前端水印
调用水印页面:
<template>
<Watermark text="版权所有">
<div>啊哈哈哈哈哈哈哈哈</div>
</Watermark>
</template>
<script setup>
import Watermark from '@/components/Watermark.vue'
</script>
水印组件:
<template>
<div class="watermark-container" ref="parentRef">
<slot></slot>
</div>
</template>
<script setup>
import { ref, watchEffect, onMounted, onUnmounted } from 'vue'
import useWatermarkBg from '../utils/useWatermarkBg'
const props = defineProps({
text: {
// 传入水印的文本
type: String,
required: true,
default: 'watermark'
},
fontSize: {
// 字体的大小
type: Number,
default: 40
},
gap: {
// 水印重复的间隔
type: Number,
default: 20
}
})
const bg = useWatermarkBg(props)
const parentRef = ref(null)
const flag = ref(0) // 声明一个依赖
let div
watchEffect(() => {
flag.value // 将依赖放在 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
parentRef.value.appendChild(div)
})
let ob
onMounted(() => {
ob = new MutationObserver((records) => {
for (const record of records) {
for (const dom of record.removedNodes) {
if (dom === div) {
flag.value++ // 删除节点的时候更新依赖
return
}
}
if (record.target === div) {
flag.value++ // 修改属性的时候更新依赖
return
}
}
})
ob.observe(parentRef.value, {
childList: true,
attributes: true,
subtree: true
})
})
onUnmounted(() => {
ob && ob.disconnect()
div = null
})
</script>
useWatermarkBg.js:
import { computed } from 'vue'
export default function useWatermarkBg(props) {
return computed(() => {
// 创建一个 canvas
const canvas = document.createElement('canvas')
const devicePixelRatio = window.devicePixelRatio || 1
// 设置字体大小
const fontSize = props.fontSize * devicePixelRatio
const font = fontSize + 'px'
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)
// 旋转 45 度让文字变倾斜
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,
styleSize: canvasSize / devicePixelRatio
}
})
}