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
Markdown
# 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!