简单通用防篡改水印组件封装(vue3)

一、项目结构

二、项目代码

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
        }
    })
}

三、运行效果

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值