uniapp h5 页面水印功能

5 阅读2分钟

业务开发中遇到展示用户隐私信息时,需要使用水印功能,以下是水印功能的业务组件,固定两列

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