UNPKG

invisible-watermark-vue

Version:

A TypeScript library for creating and detecting invisible watermarks using Canvas API, with Vue 3 support

411 lines (311 loc) 10.2 kB
# Invisible Watermark Vue 一个基于 Canvas 的隐形水印 TypeScript 库,专为 Vue 3 优化,支持创建不可见的文本水印用于追踪和版权保护。 ## 特性 - 🎯 **Vue 指令** - 提供 `v-watermark` 指令,使用超级简单 - ⚡️ **组合式 API** - 完整的 Vue 3 Composition API 支持 - 🔒 **隐形水印** - 使用极低透明度的文本创建肉眼几乎不可见的水印 - 📸 **截图追踪** - 水印在截图中保留,可用于追踪泄密源头 - 🎨 **灵活配置** - 自定义透明度、字体、旋转角度、间距等 - 🎯 **TypeScript** - 完整的类型定义支持 - 📦 **轻量级** - 核心库仅 ~3.5KB (gzipped 1.35KB) - 🛡️ **代码混淆** - 生产代码经过混淆压缩,增加安全性 ## 安装 ```bash # 使用 npm npm install invisible-watermark-vue # 使用 pnpm pnpm add invisible-watermark-vue # 使用 yarn yarn add invisible-watermark-vue ``` ## 快速开始 ### 方式一:Vue 指令(最简单 ⭐推荐) #### 1. 注册插件 ```typescript // main.ts import { createApp } from 'vue'; import { WatermarkPlugin } from 'invisible-watermark-vue'; import App from './App.vue'; const app = createApp(App); app.use(WatermarkPlugin); // 全局注册 v-watermark 指令 app.mount('#app'); ``` #### 2. 使用指令 ```vue <template> <!-- 对象语法:完整配置 --> <div v-watermark="{ text: 'user_12345', opacity: 0.005 }" class="content"> 这是受保护的内容区域 </div> <!-- 字符串简写:仅设置文本 --> <div v-watermark="'user_12345'" class="content"> 快速添加水印 </div> <!-- 响应式:动态更新 --> <div v-watermark="watermarkConfig" class="content"> 响应式水印 </div> </template> <script setup lang="ts"> import { reactive } from 'vue'; const watermarkConfig = reactive({ text: 'user_' + Date.now(), opacity: 0.005, fontSize: 20, rotate: -15, }); // 修改 watermarkConfig 会自动更新水印 function updateWatermark() { watermarkConfig.text = 'new_user_id'; watermarkConfig.opacity = 0.01; } </script> ``` #### 3. 局部注册(可选) 如果不想全局注册,也可以在组件中局部注册: ```vue <script setup lang="ts"> import { vWatermark } from 'invisible-watermark-vue'; // 在 <script setup> 中,指令会自动可用 </script> <template> <div v-watermark="'user_12345'">内容</div> </template> ``` 或使用 Options API: ```vue <script> import { vWatermark } from 'invisible-watermark-vue'; export default { directives: { watermark: vWatermark, }, }; </script> ``` ### 方式二:组合式 API 如果需要更多控制,可以使用 `useWatermark` 组合式函数: ```vue <template> <div> <div ref="containerRef" class="content"> 受保护的内容区域 </div> <button @click="apply({ text: 'user_12345', opacity: 0.005 })"> 应用水印 </button> <button @click="update({ opacity: 0.01 })">更新水印</button> <button @click="clear">清除水印</button> <p v-if="isApplied">当前水印: {{ currentText }}</p> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; import { useWatermark } from 'invisible-watermark-vue'; const containerRef = ref<HTMLElement | null>(null); const { isApplied, currentText, apply, update, clear, destroy } = useWatermark( containerRef, // 可选:组件挂载时自动应用 { text: 'user_12345', opacity: 0.005, } ); </script> ``` ### 方式三:原生 JavaScript/TypeScript 如果不使用 Vue,也可以直接使用核心类: ```typescript import { WatermarkCreator } from 'invisible-watermark-vue'; const creator = new WatermarkCreator(); const container = document.getElementById('content')!; // 应用水印 creator.apply(container, { text: 'user_12345', opacity: 0.005, fontSize: 20, rotate: -15, }); // 更新水印 creator.update({ text: 'user_67890' }); // 启用窗口大小变化时自动重绘 const cleanup = creator.enableAutoResize(); // 清除水印 creator.clear(); // 销毁水印 creator.destroy(); cleanup(); // 清理事件监听器 ``` ## API 文档 ### v-watermark 指令 ```vue <!-- 对象语法 --> <div v-watermark="WatermarkOptions">...</div> <!-- 字符串简写(仅文本) --> <div v-watermark="string">...</div> ``` **特性:** - ✅ 自动生命周期管理(mounted/updated/unmounted) - ✅ 响应式更新 - ✅ 自动调整窗口大小 - ✅ 条件渲染支持(v-if/v-show) ### WatermarkPlugin Vue 插件,用于全局注册 `v-watermark` 指令。 ```typescript import { WatermarkPlugin } from 'invisible-watermark-vue'; app.use(WatermarkPlugin); ``` ### useWatermark (组合式函数) ```typescript function useWatermark( containerRef: Ref<HTMLElement | null>, options?: WatermarkOptions ): { isApplied: Ref<boolean>; // 水印是否已应用 currentText: Ref<string>; // 当前水印文本 apply: (options?: WatermarkOptions) => void; // 应用水印 update: (options: Partial<WatermarkOptions>) => void; // 更新水印 clear: () => void; // 清除水印 destroy: () => void; // 销毁水印 } ``` ### WatermarkCreator (核心类) #### 方法 - `apply(container: HTMLElement, options: WatermarkOptions)` - 应用水印到指定容器 - `update(options: Partial<WatermarkOptions>)` - 更新水印配置 - `clear()` - 清除水印内容 - `destroy()` - 销毁水印(移除Canvas元素) - `enableAutoResize()` - 启用窗口大小变化时自动重绘,返回清理函数 - `getCurrentText()` - 获取当前水印文本 - `getCurrentOptions()` - 获取当前配置 ### WatermarkOptions (配置选项) ```typescript interface WatermarkOptions { text: string; // 水印文本内容(必填) opacity?: number; // 透明度 0-1,默认 0.005 fontSize?: number; // 字体大小,默认 20 fontFamily?: string; // 字体样式,默认 'Arial' rotate?: number; // 旋转角度(度),默认 -15 color?: string; // RGB格式颜色,默认 '0, 0, 0' spacingX?: number; // 水平间距倍数,默认 1 spacingY?: number; // 垂直间距倍数,默认 1.5 } ``` **配置说明:** - **text**: 必填,水印文本,建议使用用户ID、时间戳等唯一标识 - **opacity**: 透明度,0.005 推荐(肉眼几乎不可见),0.01 稍微可见但更容易追踪 - **fontSize**: 字体大小,影响水印密度 - **fontFamily**: 字体,建议使用系统通用字体 - **rotate**: 旋转角度,-15° 是常用值,增加隐蔽性 - **color**: RGB颜色值,默认黑色 - **spacingX/Y**: 控制水印间距,值越大间距越大 ## 使用示例 ### 示例 1:保护敏感页面 ```vue <template> <div v-watermark="userWatermark" class="sensitive-page"> <h1>机密文档</h1> <p>这里是敏感内容...</p> </div> </template> <script setup lang="ts"> import { computed } from 'vue'; import { useUserStore } from '@/stores/user'; const userStore = useUserStore(); const userWatermark = computed(() => ({ text: `${userStore.username}_${userStore.userId}_${Date.now()}`, opacity: 0.005, fontSize: 18, })); </script> ``` ### 示例 2:数据可视化保护 ```vue <template> <div v-watermark="chartWatermark" class="chart-container"> <ECharts :option="chartOption" /> </div> </template> <script setup lang="ts"> const chartWatermark = { text: 'Company Internal Data', opacity: 0.003, fontSize: 24, rotate: -20, spacingX: 1.5, spacingY: 2, }; </script> ``` ### 示例 3:条件渲染 ```vue <template> <div v-if="isInternalUser" v-watermark="`internal_${userId}`" class="content"> 内部用户专属内容 </div> </template> <script setup lang="ts"> import { ref } from 'vue'; const isInternalUser = ref(true); const userId = ref('12345'); </script> ``` ## 工作原理 ### 水印创建 1. 在目标容器上创建一个透明覆盖层 Canvas 元素 2. 使用极低透明度(如 0.005)的文本在 Canvas 上重复绘制 3. 文本以网格形式铺满整个区域,并旋转一定角度增加隐蔽性 4. 肉眼几乎无法察觉,但截图后依然保留在图像中 5. 支持高DPI屏幕,自动处理设备像素比 ### 特性 - ✅ 自动处理容器定位(如果是static会自动改为relative) - ✅ 支持窗口大小变化时自动重绘 - ✅ 高DPI屏幕适配 - ✅ 不影响页面交互(pointer-events: none) - ✅ 可动态更新水印内容 - ✅ 组件卸载时自动清理 ## 使用场景 - 🔐 **内部文档溯源** - 追踪文档泄露源头 - 📄 **防截图泄密** - 在敏感内容页面添加用户标识 - 👤 **用户行为追踪** - 记录用户访问痕迹 - 📊 **数据可视化保护** - 保护图表和数据展示 - 💼 **企业内容管理** - 标记内部文件和报告 ## 注意事项 ### 透明度设置建议 | 透明度 | 可见度 | 追踪能力 | 适用场景 | |--------|--------|----------|----------| | 0.003 | 几乎完全不可见 | 低(压缩后可能丢失) | 极度敏感内容 | | 0.005 | 肉眼基本不可见 | 中等 | **推荐,一般使用** | | 0.01 | 细看可能察觉 | 高 | 需要强追踪能力 | ### 最佳实践 1. **截图格式**: 建议使用 PNG 格式,JPG 压缩可能损失水印 2. **水印文本**: 使用唯一标识符(用户ID、时间戳、会话ID等) 3. **后端记录**: 配合后端记录"用户→水印文本"映射,便于追溯 4. **多层防护**: 结合其他安全措施(访问控制、日志记录等) ### 兼容性 - ✅ 现代浏览器(支持 Canvas API) - ✅ Vue 3.x - ✅ TypeScript 5.x - ✅ 支持 ESM 和 CommonJS ## 开发 ```bash # 安装依赖 pnpm install # 开发模式(监听文件变化) pnpm run dev # 构建(包含代码混淆) pnpm run build ``` ## 构建产物 - `dist/index.js` - ESM 格式(混淆压缩) - `dist/index.cjs` - CommonJS 格式(混淆压缩) - `dist/index.d.ts` - TypeScript 类型定义 - `dist/index.d.cts` - CommonJS TypeScript 类型定义 - 包含 Source Maps ## License MIT ## 贡献 欢迎提交 Issue 和 Pull Request!