一、自定义指令的方式
javascript
/*
需求:给整个页面添加背景水印。
思路:
1、使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。
2、将其设置为背景图片,从而实现页面或组件水印效果
使用:设置水印文案,颜色,字体大小即可
<div v-waterMarker="{text:'版权所有',textColor:'rgba(180, 180, 180, 0.4)'}"></div>
*/
const addWaterMarker = (str, parentNode, font, textColor) => {
// 水印文字,父元素,字体,文字颜色
let can = document.createElement("canvas");
parentNode.appendChild(can);
can.width = 205;
can.height = 140;
can.style.display = "none";
let cans = can.getContext("2d");
cans.rotate((-20 * Math.PI) / 180);
cans.font = font || "16px Microsoft JhengHei";
cans.fillStyle = textColor || "rgba(180, 180, 180, 0.3)";
cans.textAlign = "left";
cans.textBaseline = "Middle";
cans.fillText(str, can.width / 10, can.height / 2);
parentNode.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")";
};
const waterMarker = {
mounted(el, binding) {
addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor);
}
};
export default waterMarker;
二、组件的方式
html
<template>
<WaterMark watermark-text="你好你好你好">
<div class="content">我这里是水印</div>
</WaterMark>
</template>
<script setup lang="ts">
import WaterMark from "./WaterMark.vue";
</script>
<style scoped>
.content {
display: flex;
justify-content: space-around;
width: 100%;
}
</style>
html
//./WaterMark.vue
<template>
<div ref="watermarkContainer" class="watermark-container">
<!-- 插槽内容,可以放置需要水印的内容 -->
<slot></slot>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref, Ref, watch } from "vue";
// 定义Props
// defineProps<{ watermarkText: string }>();
const props = defineProps({
watermarkText: {
type: String,
required: true,
default: "默认水印",
},
});
// const watermarkUrl: Ref<string> = ref("");
const watermarkContainer = ref<HTMLElement | null>(null);
const watermark = ref<HTMLDivElement | null>(null);
const drawWatermark = () => {
console.log("drawWatermark----");
const watermarkImage = getWatermarkImage();
if (watermark.value) {
watermark.value.remove();
}
watermark.value = document.createElement("div");
watermark.value.style.position = "absolute";
watermark.value.style.backgroundImage = `url(${watermarkImage})`;
watermark.value.style.backgroundSize = "200px 200px";
watermark.value.style.backgroundRepeat = "repeat";
// watermark.value.style.opacity = "0.5";
watermark.value.style.zIndex = "99";
watermark.value.style.pointerEvents = "none";
watermark.value.style.transform = "rotate(-45deg)";
watermark.value.style.inset = "0";
watermarkContainer.value?.appendChild(watermark.value);
};
const getWatermarkImage = () => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) return;
canvas.width = 200;
canvas.height = 150;
ctx.font = "16px Arial";
ctx.fillStyle = "rgba(184, 184, 184, 0.5)";
// ctx.textAlign = "center";
ctx.fillText(props.watermarkText, 20, 100);
return canvas.toDataURL("image/png");
};
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
console.log(mutation);
if (
mutation.type === "attributes" ||
mutation.attributeName === "style"
) {
drawWatermark();
}
});
});
onMounted(() => {
drawWatermark();
if (watermarkContainer.value) {
observer.observe(watermarkContainer.value, {
childList: true,
subtree: true,
attributes: true,
// attributeFilter: ["style"],
});
}
watch(
() => props.watermarkText,
() => {
drawWatermark();
},
);
});
onUnmounted(() => {
observer.disconnect();
});
</script>
<style>
.watermark-container {
position: relative;
width: 100%;
height: 100%;
}
</style>