简单手写背景水印组件

112 阅读1分钟

主要使用 MutationObserver 监听元素是否被删除或样式被修改,如果有则重新生成水印

一、html部分

<template>
  <div ref="parentRef" class="watermark-container">
    <slot/>
  </div>
</template>

二、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
        }
    })
}
<script setup>
import useWatermarkBg from "@components/copyright/useWatermarkBg.js";
import {onMounted, onUnmounted, ref} from "vue";

const props = defineProps({
  text: {
    type: String,
    required: true,
    default: "watermark"
  },
  fontSize: {
    type: Number,
    default: 40,
  },
  gap: {
    type: Number,
    default: 10
  }
})

const bg = useWatermarkBg(props);
// console.log(bg)
const parentRef = ref(null);
let div;

// 重置水印
function resetWatermark() {
  if (!parentRef.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}`;
  div.style.backgroundRepeat = "repeat";
  div.style.zIndex = 9;
  div.style.inset = 0;
  parentRef.value.appendChild(div)
}

onMounted(resetWatermark);

const ob = new MutationObserver(entries => {
  for (const entry of entries){
    // 删除节点触发
    for(const dom of entry.removedNodes){
      if(dom === div){
        console.log("水印被删除")
        resetWatermark();
        return
      }
    }
    // 修改属性触发
    if(entry.target === div){
      console.log("属性被修改了")
      resetWatermark();
      return;
    }
  }
})

onMounted(() => {
  // console.log(parentRef.value)
  ob.observe(parentRef.value, {
    // 监控子节点
    childList: true,
    // 监控子树
    subtree: true,
    attributes: true,
  })
})

onUnmounted(() => {
  ob.disconnect();
})
</script>

三、css部分

<style scoped>
.watermark-container {
  width: 100%;
  height: 100%;
  position: relative;
}
</style>