当前位置: 首页 > java >正文

vue 水印组件

Watermark.vue

<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';interface Props {text?: string;fontSize?: number;color?: string;rotate?: number;zIndex?: number;gap?: number;
}const props = withDefaults(defineProps<Props>(), {text: 'Watermark',fontSize: 16,color: 'rgba(0, 0, 0, 0.1)',rotate: -45,zIndex: 1000,gap: 100
});const watermarkRef = ref<HTMLDivElement>();
const containerRef = ref<HTMLDivElement>();
let observer: MutationObserver | null = null;
let styleObserver: MutationObserver | null = null;
let securityInterval: number | null = null;const createWatermark = () => {const canvas = document.createElement('canvas');const ctx = canvas.getContext('2d');if (!ctx) return '';ctx.font = `${props.fontSize}px Arial`;const textWidth = ctx.measureText(props.text).width;const width = textWidth + props.gap;const height = props.fontSize + props.gap;canvas.width = width;canvas.height = height;ctx.translate(width / 2, height / 2);ctx.rotate((props.rotate * Math.PI) / 180);ctx.font = `${props.fontSize}px Arial`;ctx.fillStyle = props.color;ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText(props.text, 0, 0);return canvas.toDataURL();
};const applyWatermark = () => {if (!watermarkRef.value) return;const url = createWatermark();const originalStyles = {position: 'absolute',top: '0',left: '0',width: '100%',height: '100%',pointerEvents: 'none',backgroundImage: `url(${url})`,backgroundRepeat: 'repeat',userSelect: 'none',webkitUserSelect: 'none',zIndex: props.zIndex.toString(),opacity: '1',display: 'block',visibility: 'visible'};Object.assign(watermarkRef.value.style, originalStyles);
};const observeContainer = () => {if (!containerRef.value || !watermarkRef.value) return;observer = new MutationObserver((mutations) => {mutations.forEach((mutation) => {if (mutation.type === 'childList') {const removedNodes = Array.from(mutation.removedNodes);if (removedNodes.includes(watermarkRef.value!)) {containerRef.value?.appendChild(watermarkRef.value!);applyWatermark();}}});});observer.observe(containerRef.value, {childList: true,subtree: true,attributes: true});
};const observeWatermark = () => {if (!watermarkRef.value) return;styleObserver = new MutationObserver(() => {applyWatermark();});styleObserver.observe(watermarkRef.value, {attributes: true,attributeFilter: ['style', 'class']});
};const startSecurityCheck = () => {securityInterval = window.setInterval(() => {if (!watermarkRef.value?.isConnected) {containerRef.value?.appendChild(watermarkRef.value!);}applyWatermark();}, 100) as unknown as number;
};watch(() => [props.text, props.fontSize, props.color, props.rotate, props.gap], () => {applyWatermark();
});onMounted(() => {applyWatermark();observeContainer();observeWatermark();startSecurityCheck();
});onUnmounted(() => {observer?.disconnect();styleObserver?.disconnect();if (securityInterval) {clearInterval(securityInterval);}
});
</script><template><div ref="containerRef" class="watermark-container"><div ref="watermarkRef" class="watermark"></div><div class="content"><slot></slot></div></div>
</template><style scoped>
.watermark-container {position: relative;width: 100%;height: 100%;
}.watermark {position: absolute;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none;background-repeat: repeat;user-select: none;-webkit-user-select: none;
}.content {position: relative;width: 100%;height: 100%;
}
</style>

http://www.xdnf.cn/news/8406.html

相关文章:

  • 【Dv3Admin】插件 dv3admin_chatgpt 优化支持多种启动方式实现SSE效果
  • QT之巧用对象充当信号接收者
  • Linux进程 线程 进程间通信 IPC——管道
  • 全国青少年信息素养大赛-python编程—省赛真题—卡牌游戏
  • Redis配置文件详解
  • 树 Part 10
  • JFace中MVC的表的单元格编辑功能的实现
  • Datawhale_PyPOTS_task6
  • 【安全攻防与漏洞​】​​HTTPS中的常见攻击与防御​​
  • 机器人强化学习入门学习笔记(三)
  • 洛谷 P1800 software(DP+二分)【提高+/省选−】
  • 三步快速部署一个本地Windows/Linux大语言模型ChatGLM(环境配置+权重下载+运行)
  • AI架构分层原则
  • Stack主题遇到的问题
  • C# WinForm应用程序多语言实现全面指南
  • deepseek组合使用
  • 测试关键点
  • 【Kafka】编写消费者开发模式时遇到‘未解析的引用‘SIGUSR1’’
  • 掌握递归:编程中的优雅艺术
  • 精益数据分析(79/126):从黏性到爆发——病毒性增长的三种形态与核心指标解析
  • Swagger、Springfox、Springdoc-openapi 到底是什么关系
  • 使用 GPUStack 纳管摩尔线程 GPU 进行大语言模型和文生图模型的推理
  • ASPICE认证 vs. 其他标准:汽车软件开发的最优选择
  • C# UDP协议:核心原理、高效实现与实战进阶指南​
  • 2025语音语聊系统源码开发深度解析:WebRTC与AI降噪技术如何重塑语音社交体验
  • 智能存储如何应对极端环境挑战?忆联独家解锁PCIe 5.0固态存储“抗辐射”黑科技,重新定义数据安全防护新高度
  • 机会成本与沉没成本:如何做出理性经济决策
  • grafana/loki-stack 设置日志保存时间及自动清理
  • HarmonyOS NEXT~鸿蒙AI开发全解析:HarmonyOS SDK中的智能能力与应用实践
  • PCB设计教程【入门篇】——电路分析基础-读懂原理图