业务开发中遇到展示用户隐私信息时,需要使用水印功能,以下是水印功能的业务组件,固定两列
<template>
<view
class="watermark-container"
v-if="show"
:style="{
opacity: opacity,
'z-index': zIndex,
}"
>
<!-- 水印网格容器 -->
<view class="watermark-grid">
<!-- 循环生成水印文本,动态计算每行偏移 -->
<text
class="watermark-text"
v-for="(item, index) in totalCount"
:key="index"
:style="{
color: fontColor,
fontSize: fontSize + 'px',
transform: `rotate(${rotate}deg)`,
fontFamily: fontFamily,
// 核心:奇数行/偶数行设置不同的左侧偏移
marginLeft: `${getRowOffset(index)}`,
// 固定每个水印的宽度,确保排列整齐
width: `40%`,
}"
>
{{ textContent }}
</text>
</view>
</view>
</template>
<script>
export default {
name: "WatermarkText",
props: {
// 是否显示水印
show: {
type: Boolean,
default: true,
},
// 水印文案(单行)
text: {
type: String,
default: "默认水印",
},
// 字体大小(px)
fontSize: {
type: Number,
default: 14,
},
// 字体颜色
fontColor: {
type: String,
default: "rgba(0, 0, 0, 0.15)",
},
// 旋转角度(角度制,负数向左旋)
rotate: {
type: Number,
default: -25,
},
// 整体透明度
opacity: {
type: Number,
default: 1,
},
// 字体
fontFamily: {
type: String,
default: "Microsoft Yahei",
},
// 水印层级
zIndex: {
type: Number,
default: 99999,
},
},
data() {
return {
textContent: "",
totalCount: 0, // 水印总数量
colCount: 0, // 列数(缓存,用于计算行号)
resizeObserver: null, // 用于监听父元素大小变化
};
},
watch: {
// 监听属性变化,重新生成水印
text: {
immediate: true,
handler(val) {
this.textContent = val;
this.calcWatermarkCount();
},
},
show(val) {
if (val) {
// 页面渲染完成后计算数量,避免尺寸获取错误
this.$nextTick(() => {
this.calcWatermarkCount();
});
}
},
},
mounted() {
if (this.show) {
this.$nextTick(() => {
this.calcWatermarkCount();
});
}
// 使用 ResizeObserver 监听父元素大小变化(替代 window.resize)
const parentElement = this.$el?.parentElement;
if (parentElement) {
this.resizeObserver = new ResizeObserver(() => {
this.calcWatermarkCount();
});
this.resizeObserver.observe(parentElement);
}
},
beforeDestroy() {
// 移除 ResizeObserver 监听,避免内存泄漏
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
},
methods: {
// 计算需要生成的水印数量(根据屏幕尺寸和间距)
calcWatermarkCount() {
if (!this.show) return;
// 获取父元素尺寸(替代 window.innerWidth/innerHeight)
const parentElement = this.$el?.parentElement;
if (!parentElement) return;
const parentWidth = parentElement.clientWidth;
const parentHeight = parentElement.clientHeight;
// 计算行列数(多算 2 行/列,确保全屏覆盖)
this.colCount = 2; // 固定一行两个
const rowCount = Math.ceil(parentHeight / 100);
// 总数量 = 行数 * 列数
this.totalCount = this.colCount * rowCount;
},
// 计算每行的左侧偏移量(核心:相邻行偏移不同)
getRowOffset(index) {
// 计算当前水印属于第几行
const rowIndex = Math.floor(index / this.colCount);
// 定义偏移量:默认是gap的一半,也可通过props自定义
const offsetValue = "10%";
// 奇数行偏移,偶数行不偏移(反之亦可)
return rowIndex % 2 === 1 ? offsetValue : 0;
},
},
};
</script>
<style scoped lang="scss">
// 水印容器:全屏固定定位,不拦截交互
.watermark-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; // 关键:不影响页面点击/滑动
overflow: hidden;
}
// 水印网格:通过flex-wrap实现换行,适配错位排列
.watermark-grid {
display: flex;
width: 100%;
height: 100%;
flex-wrap: wrap;
// 取消默认间距,通过marginLeft控制偏移
gap: 0;
}
// 水印文字样式
.watermark-text {
display: flex;
align-items: center;
// 禁止文字选中
user-select: none;
// 确保文字不会换行
white-space: nowrap;
// 抗锯齿,让文字更清晰
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
// 去掉默认边距
margin: 0;
padding: 0;
justify-content: center;
height: 200rpx;
}
</style>
页面使用方法
<WaterMark
:show="true"
text="水印"
:font-size="14"
font-color="rgba(0,0,0,.15)"
:rotate="-25"
:z-index="9999"
></WaterMark>