项目需求前端在图片上做一些水印,在网上找了很多资料发现都不是很好用,这里自己根据找到的资料优化合成了一个组件。
效果预览
组件watermark.vue
<template>
<div class="watermark" id="watermark">
<div ref="watermarkContainer" class="watermark-container"></div>
</div>
</template>
<script>
export default {
name: "Watermark",
props: {
// 水印内容
content: {
type: String,
default: "Watermark",
},
// 水印字体大小
fontSize: {
type: Number,
default:24,
},
// 水印透明度
alpha: {
type: Number,
default: 0.2,
},
// 水印间隔
gap: {
type: Number,
default:100,
},
rotate:{
type:Number,
default:40
}
},
mounted() {
this.addWatermark();
this.observeChanges();
},
methods: {
// 生成水印图片
generateWatermark() {
console.log(this.fontSize,'this.fontSize')
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// 设置 canvas 大小
canvas.width = 200;
canvas.height = 100;
// 设置字体样式
console.log(this.fontSize,'this.fontSize')
ctx.font = `${this.fontSize}px Arial`;
ctx.fillStyle = `rgba(0, 0, 0, ${this.alpha})`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.rotate(-Math.PI / this.rotate);
// 绘制水印内容
ctx.fillText(this.content, canvas.width / 2, canvas.height / 2);
// 将 canvas 转换为 base64 图片
return canvas.toDataURL("image/png");
},
// 添加水印
addWatermark() {
const watermarkUrl = this.generateWatermark();
const container = this.$refs.watermarkContainer;
container.style.backgroundImage = `url(${watermarkUrl})`;
container.style.backgroundRepeat = "repeat";
container.style.backgroundSize = `${this.gap}px ${this.gap}px`;
},
// 观察容器变化
observeChanges() {
const wrapper = this.$refs.watermarkContainer;
const watermark = document.getElementById("watermark");
const config = {
attributes: true,
childList: true,
subtree: true,
attributeFilter: ["style", "class"],
};
this.observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
// 防止删除水
if (mutation.removedNodes) {
mutation.removedNodes.forEach((node) => {
if (node === wrapper) {
const wrapper1 = document.createElement("div");
wrapper1.style.position = "absolute";
wrapper1.style.top = "0";
wrapper1.style.left = "0";
wrapper1.style.width = "100%";
wrapper1.style.height = "100%";
wrapper1.style.zIndex = "9999";
wrapper1.style.backgroundImage = `url(${this.generateWatermark()})`;
wrapper1.style.backgroundRepeat = "repeat";
wrapper1.style.backgroundSize = `${this.gap}px ${this.gap}px`;
watermark.appendChild(wrapper1);
}
});
}
// 防止修改css
if (mutation.type === "attributes") {
wrapper.style.opacity = "1";
wrapper.style.visibility = "visible";
wrapper.style.display = "block";
wrapper.style.backgroundSize = `${this.gap}px ${this.gap}px`;
}
});
});
this.observer.observe(wrapper.parentNode, config);
},
},
};
</script>
<style scoped>
.watermark-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
pointer-events: none;
z-index: 9999;
}
</style>
父组件
<div class="ww-img-box">
<Watermark></Watermark>
<img
:src="item.ww_firstimg"
alt=""
@error="imgErrorHandler(index)"
class="ww-img"
/>
/div>