Waterwrapper.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <!-- 水印容器:根据传入的 props 适配全局/局部水印 -->
  3. <div
  4. class="watermark-wrapper"
  5. :style="{
  6. position: position,
  7. top: 0,
  8. left: 0,
  9. width: width,
  10. height: height,
  11. zIndex: zIndex,
  12. pointerEvents: 'none' // 核心:不遮挡交互
  13. }"
  14. ></div>
  15. </template>
  16. <script setup>
  17. import { ref, onMounted, onUnmounted, watch } from 'vue';
  18. // import {useUserInfoHook} from '@/hooks/useUserInfoHook'
  19. // 定义组件 props
  20. const props = defineProps({
  21. // 定位方式:fixed(全局)/ absolute(局部)
  22. position: {
  23. type: String,
  24. default: 'fixed',
  25. validator: (val) => ['fixed', 'absolute'].includes(val)
  26. },
  27. // 宽度:全局用 100vw,局部用 100%
  28. width: {
  29. type: String,
  30. default: '100vw'
  31. },
  32. // 高度:全局用 100vh,局部用 100%
  33. height: {
  34. type: String,
  35. default: '100vh'
  36. },
  37. // 层级:默认 999(低于 el-dialog 的 2000)
  38. zIndex: {
  39. type: Number,
  40. default: 999
  41. },
  42. // 是否固定屏幕模式(适配你的业务逻辑)
  43. isFixedScreen: {
  44. type: Boolean,
  45. default: false
  46. },
  47. username:{
  48. type: String,
  49. },
  50. realname:{
  51. type: String,
  52. }
  53. });
  54. // 移除水印的方法引用
  55. let removeWatermarkFn = null;
  56. // 获取用户仓库
  57. // const {realname,staffNo} = useUserInfoHook();
  58. // 生成水印的核心方法
  59. const createWatermark = () => {
  60. // 未登录/无用户信息时不生成水印
  61. if (!props.username || !props.realname) return;
  62. // 拼接水印文本
  63. const watermarkText = `${props.username}-${props.realname}`;
  64. // 1. 创建 Canvas 绘制水印
  65. const canvas = document.createElement('canvas');
  66. const ctx = canvas.getContext('2d');
  67. if (!ctx) return;
  68. // 配置水印样式
  69. const font = '16px Microsoft YaHei';
  70. const color = 'rgba(64, 158, 255, 0.15)';
  71. const rotate = -15;
  72. // 计算文本尺寸
  73. ctx.font = font;
  74. const textWidth = ctx.measureText(watermarkText).width;
  75. canvas.width = textWidth + 120; // 水平间距
  76. canvas.height = textWidth + 80; // 垂直间距
  77. // 绘制水印
  78. ctx.font = font;
  79. ctx.fillStyle = color;
  80. ctx.rotate((rotate * Math.PI) / 180); // 角度转弧度
  81. ctx.fillText(watermarkText, 0, canvas.height / 2);
  82. // 2. 生成 Base64 图片
  83. const watermarkBase64 = canvas.toDataURL('image/png');
  84. // 3. 给水印容器设置背景
  85. const wrapper = document.querySelector('.watermark-wrapper');
  86. if (wrapper) {
  87. wrapper.style.backgroundImage = `url(${watermarkBase64})`;
  88. wrapper.style.backgroundRepeat = 'repeat';
  89. wrapper.style.backgroundSize = `${canvas.width}px ${canvas.height}px`;
  90. }
  91. };
  92. // 移除水印
  93. const removeWatermark = () => {
  94. const wrapper = document.querySelector('.watermark-wrapper');
  95. if (wrapper) {
  96. wrapper.style.backgroundImage = 'none';
  97. }
  98. };
  99. // 监听用户信息变化(登录/退出时重新生成水印)
  100. // watch(
  101. // () => userId,
  102. // () => {
  103. // removeWatermark();
  104. // createWatermark();
  105. // },
  106. // { immediate: true, deep: true }
  107. // );
  108. // 监听 isFixedScreen 变化,适配布局
  109. // watch(
  110. // () => props.isFixedScreen,
  111. // () => {
  112. // removeWatermark();
  113. // createWatermark();
  114. // }
  115. // );
  116. // 页面挂载时生成水印
  117. onMounted(() => {
  118. createWatermark();
  119. });
  120. // 页面销毁时移除水印
  121. onUnmounted(() => {
  122. removeWatermark();
  123. if (removeWatermarkFn) {
  124. removeWatermarkFn();
  125. }
  126. });
  127. </script>
  128. <style scoped>
  129. .watermark-wrapper {
  130. width: 100vw;
  131. height: 100vh;
  132. margin: 0;
  133. padding: 0;
  134. border: none;
  135. background: transparent;
  136. }
  137. </style>