vue3-electronic-signature
Version:
一个基于Vue3的电子签名组件库,支持手写签名、触摸绘制和多种导出格式
710 lines (576 loc) • 19.9 kB
Markdown
# Vue3 电子签名组件库
一个功能强大、易于使用的Vue3电子签名组件库,支持手写签名、触摸绘制和多种导出格式。
## ✨ 特性
- 🖊️ **流畅绘制** - 基于Canvas的高性能绘图引擎,连续流畅的书写体验
- 📱 **移动端支持** - 完美支持触摸设备和手势操作
- 🎨 **多种笔迹样式** - 适中笔迹(默认)、优雅笔迹、毛笔、铅笔等专业笔迹效果
- ✨ **智能渐变** - 优雅笔迹支持基于速度和压力的由粗到细渐变效果
- 🚫 **无闪烁渲染** - 所有笔迹样式都支持稳定的实时渲染,无闪烁干扰
- 📤 **多格式导出** - 支持PNG、JPEG、SVG、Base64等格式
- 🔄 **撤销重做** - 完整的操作历史管理
- 📏 **响应式设计** - 自适应容器尺寸
- 💪 **TypeScript** - 完整的类型定义支持
- 🎯 **压感模拟** - 根据绘制速度模拟压感效果
- 🖼️ **图像处理** - 内置裁剪、缩放、水印等功能
- 🎬 **签名回放** - 支持签名路径的录制和回放功能,保持笔迹样式一致性
## 📦 安装
```bash
npm install vue3-electronic-signature
```
或者使用 yarn:
```bash
yarn add vue3-electronic-signature
```
## 🚀 快速开始
### 全局注册
```typescript
import { createApp } from 'vue'
import Vue3ElectronicSignature from 'vue3-electronic-signature'
import App from './App.vue'
const app = createApp(App)
app.use(Vue3ElectronicSignature)
app.mount('#app')
```
### 局部引入
```vue
<template>
<ElectronicSignature
:width="400"
:height="200"
placeholder="请在此处签名"
@signature-end="onSignatureEnd"
/>
</template>
<script setup lang="ts">
import { ElectronicSignature } from 'vue3-electronic-signature'
import type { SignatureData } from 'vue3-electronic-signature'
const onSignatureEnd = (data: SignatureData) => {
console.log('签名完成', data)
}
</script>
```
## 📖 基础用法
### 简单签名
```vue
<template>
<ElectronicSignature
:width="400"
:height="200"
stroke-color="#000000"
:stroke-width="2"
placeholder="请在此处签名"
/>
</template>
```
### 笔迹样式选择
```vue
<template>
<div>
<!-- 样式选择器 -->
<select v-model="selectedPenStyle">
<option value="ballpoint">适中笔迹 - 连续流畅,商务首选(默认)</option>
<option value="elegant">优雅笔迹 - 智能渐变,由粗到细</option>
<option value="brush">毛笔 - 传统书法,自然变化</option>
<option value="pencil">铅笔 - 稳定连续,素描效果</option>
<option value="pen">钢笔 - 极细锐利,精准线条</option>
<option value="marker">马克笔 - 超粗荧光,醒目标记</option>
</select>
<!-- 签名组件 -->
<ElectronicSignature
:width="400"
:height="200"
:pen-style="selectedPenStyle"
stroke-color="#2c3e50"
placeholder="选择不同笔迹样式体验"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ElectronicSignature } from 'vue3-electronic-signature'
import type { PenStyle } from 'vue3-electronic-signature'
const selectedPenStyle = ref<PenStyle>('ballpoint') // 默认适中笔迹
</script>
```
### 自定义样式
```vue
<template>
<ElectronicSignature
:width="500"
:height="300"
stroke-color="#2196F3"
:stroke-width="3"
background-color="#FFFEF7"
border-style="2px solid #2196F3"
border-radius="8px"
:smoothing="true"
:pressure-sensitive="true"
placeholder="自定义样式签名"
/>
</template>
```
### 响应式签名
```vue
<template>
<ElectronicSignature
width="100%"
:height="200"
stroke-color="#4CAF50"
placeholder="响应式签名区域"
/>
</template>
```
## 🔧 API 文档
### Props 属性
| 属性名 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| width | number \| string | '100%' | 画布宽度 |
| height | number \| string | 300 | 画布高度 |
| **penStyle** | **PenStyle** | **'ballpoint'** | **笔迹样式:'ballpoint'(适中) \| 'elegant'(优雅) \| 'brush'(毛笔) \| 'pencil'(铅笔) \| 'pen'(钢笔) \| 'marker'(马克笔)** |
| strokeColor | string | '#000000' | 画笔颜色 |
| strokeWidth | number | 2 | 画笔粗细(部分样式会覆盖此设置) |
| backgroundColor | string | 'transparent' | 背景颜色 |
| disabled | boolean | false | 是否禁用 |
| placeholder | string | '请在此处签名' | 占位符文本 |
| smoothing | boolean | true | 是否启用平滑绘制(部分样式会覆盖此设置) |
| pressureSensitive | boolean | false | 是否启用压感效果(部分样式会覆盖此设置) |
| minStrokeWidth | number | 1 | 最小画笔宽度(压感模式) |
| maxStrokeWidth | number | 4 | 最大画笔宽度(压感模式) |
| borderStyle | string | '1px solid #ddd' | 边框样式 |
| borderRadius | string | '4px' | 圆角大小 |
| showToolbar | boolean | false | 是否显示工具栏 |
| replayMode | boolean | false | 是否启用回放模式 |
| replayData | SignatureReplay | - | 回放数据 |
| replayOptions | ReplayOptions | - | 回放选项配置 |
### Events 事件
| 事件名 | 参数 | 说明 |
|--------|------|------|
| signature-start | - | 开始签名时触发 |
| signature-drawing | (data: SignatureData) | 签名进行中触发 |
| signature-end | (data: SignatureData) | 签名结束时触发 |
| signature-clear | - | 清除签名时触发 |
| signature-undo | (data: SignatureData) | 撤销操作时触发 |
| signature-redo | (data: SignatureData) | 重做操作时触发 |
| replay-start | - | 回放开始时触发 |
| replay-progress | (progress: number, currentTime: number) | 回放进度更新时触发 |
| replay-pause | - | 回放暂停时触发 |
| replay-resume | - | 回放恢复时触发 |
| replay-stop | - | 回放停止时触发 |
| replay-complete | - | 回放完成时触发 |
| replay-path-start | (pathIndex: number, path: SignaturePath) | 笔画开始时触发 |
| replay-path-end | (pathIndex: number, path: SignaturePath) | 笔画结束时触发 |
| replay-speed-change | (speed: number) | 回放速度改变时触发 |
### Methods 方法
| 方法名 | 参数 | 返回值 | 说明 |
|--------|------|--------|------|
| clear() | - | void | 清除签名 |
| undo() | - | void | 撤销上一步操作 |
| redo() | - | void | 重做操作 |
| save(options?) | ExportOptions | string | 保存签名 |
| isEmpty() | - | boolean | 判断签名是否为空 |
| fromDataURL(dataURL) | string | Promise\<void\> | 从数据URL加载签名 |
| getSignatureData() | - | SignatureData | 获取签名数据 |
| setSignatureData(data) | SignatureData | void | 设置签名数据 |
| resize(width?, height?) | number?, number? | void | 调整画布尺寸 |
| startReplay(data, options?) | SignatureReplay, ReplayOptions? | void | 开始回放签名 |
| getReplayData() | - | SignatureReplay \| null | 获取回放数据 |
| setReplayMode(enabled) | boolean | void | 设置回放模式 |
| play() | - | void | 播放回放 |
| pause() | - | void | 暂停回放 |
| stop() | - | void | 停止回放 |
| seek(time) | number | void | 跳转到指定时间 |
| setSpeed(speed) | number | void | 设置回放速度 |
| getState() | - | ReplayState | 获取回放状态 |
| getCurrentTime() | - | number | 获取当前回放时间 |
| getTotalDuration() | - | number | 获取总回放时长 |
| getProgress() | - | number | 获取回放进度(0-1) |
### 🎨 笔迹样式详解
| 样式 | 特点 | 视觉效果 | 适用场景 |
|------|------|----------|----------|
| **ballpoint** ⭐ | 连续流畅线条(2px) | 简洁专业,圆润收笔 | 商务签名、日常使用(默认) |
| **elegant** ✨ | 智能渐变(0.3-15px) | 由粗到细,速度感应 | 艺术签名、书法体验 |
| **brush** 🖌️ | 传统毛笔(1-20px) | 自然变化,书法韵味 | 传统书法、艺术创作 |
| **pencil** ✏️ | 稳定连续(2-5px) | 简洁清晰,无纹理 | 草稿签名、自然书写 |
| **pen** 🖊️ | 极细锐利线条(1px) | 商务精准,无圆角端点 | 精密绘图、技术签名 |
| **marker** 🖍️ | 超粗荧光效果(12px) | 荧光光晕,醒目标记 | 重点标记、醒目签名 |
#### 笔迹样式配置
```typescript
import { getAllPenStyles, getPenStyleConfig } from 'vue3-electronic-signature'
// 获取所有可用样式
const allStyles = getAllPenStyles()
// 获取特定样式配置
const penConfig = getPenStyleConfig('elegant')
console.log(penConfig)
// {
// name: '优雅笔迹',
// description: '智能渐变,由粗到细,速度感应',
// strokeWidth: 3,
// smoothing: true,
// pressure: { enabled: true, min: 1, max: 16 },
// lineCap: 'round',
// lineJoin: 'round',
// recommendedColor: '#2c3e50'
// }
```
## 📋 类型定义
### PenStyle
```typescript
type PenStyle = 'ballpoint' | 'elegant' | 'brush' | 'pencil' | 'pen' | 'marker'
```
### PenStyleConfig
```typescript
interface PenStyleConfig {
name: string // 样式名称
description: string // 样式描述
strokeWidth: number // 基础线宽
smoothing: boolean // 是否启用平滑
pressure: { // 压感配置
enabled: boolean
min: number
max: number
}
lineCap: CanvasLineCap // 线条端点样式
lineJoin: CanvasLineJoin // 线条连接样式
recommendedColor?: string // 推荐颜色
}
```
### SignatureData
```typescript
interface SignatureData {
paths: SignaturePath[] // 签名路径集合
canvasSize: { // 画布尺寸
width: number
height: number
}
timestamp: number // 创建时间戳
isEmpty: boolean // 是否为空
}
```
### ExportOptions
```typescript
interface ExportOptions {
format: 'png' | 'jpeg' | 'svg' | 'base64' // 导出格式
quality?: number // 图片质量(0-1)
size?: { // 导出尺寸
width: number
height: number
}
backgroundColor?: string // 背景颜色
}
```
### SignatureReplay
```typescript
interface SignatureReplay {
paths: SignaturePath[] // 带时间信息的路径集合
totalDuration: number // 总回放时长(毫秒)
speed: number // 回放速度倍率
metadata: { // 签名元数据
deviceType: 'mouse' | 'touch' | 'pen'
averageSpeed: number // 平均书写速度(像素/秒)
totalDistance: number // 总绘制距离(像素)
averagePauseTime: number // 笔画间平均停顿时间(毫秒)
}
}
```
### ReplayOptions
```typescript
interface ReplayOptions {
speed?: number // 回放速度倍率
loop?: boolean // 是否循环播放
showControls?: boolean // 是否显示控制条
autoPlay?: boolean // 是否自动开始播放
startTime?: number // 回放开始时间(毫秒)
endTime?: number // 回放结束时间(毫秒)
}
```
### ReplayState
```typescript
type ReplayState = 'idle' | 'playing' | 'paused' | 'stopped' | 'completed'
```
## � 签名回放功能
### 基础回放
```vue
<template>
<div>
<!-- 签名组件 -->
<ElectronicSignature
ref="signatureRef"
:width="400"
:height="200"
@signature-end="onSignatureEnd"
/>
<!-- 回放组件 -->
<ElectronicSignature
:width="400"
:height="200"
:replay-mode="true"
:replay-data="replayData"
:replay-options="replayOptions"
@replay-complete="onReplayComplete"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SignatureMethods, SignatureData, SignatureReplay } from 'vue3-electronic-signature'
const signatureRef = ref<SignatureMethods>()
const replayData = ref<SignatureReplay | null>(null)
const replayOptions = {
speed: 1,
loop: false,
showControls: true,
autoPlay: true
}
const onSignatureEnd = (data: SignatureData) => {
// 从签名数据生成回放数据
replayData.value = signatureRef.value?.getReplayData() || null
}
const onReplayComplete = () => {
console.log('回放完成')
}
</script>
```
### 手动控制回放
```vue
<template>
<div>
<ElectronicSignature
ref="replayRef"
:width="400"
:height="200"
:replay-mode="true"
:replay-data="replayData"
:replay-options="{ showControls: false, autoPlay: false }"
@replay-progress="onProgress"
/>
<!-- 自定义控制按钮 -->
<div class="custom-controls">
<button @click="play">播放</button>
<button @click="pause">暂停</button>
<button @click="stop">停止</button>
<button @click="setSpeed(0.5)">0.5x</button>
<button @click="setSpeed(1)">1x</button>
<button @click="setSpeed(2)">2x</button>
</div>
<div>进度: {{ Math.round(progress * 100) }}%</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SignatureMethods } from 'vue3-electronic-signature'
const replayRef = ref<SignatureMethods>()
const progress = ref(0)
const play = () => replayRef.value?.play()
const pause = () => replayRef.value?.pause()
const stop = () => replayRef.value?.stop()
const setSpeed = (speed: number) => replayRef.value?.setSpeed(speed)
const onProgress = (progressValue: number) => {
progress.value = progressValue
}
</script>
```
### 回放事件监听
```vue
<template>
<ElectronicSignature
:replay-mode="true"
:replay-data="replayData"
@replay-start="onReplayStart"
@replay-path-start="onPathStart"
@replay-path-end="onPathEnd"
@replay-complete="onReplayComplete"
/>
</template>
<script setup lang="ts">
import type { SignaturePath } from 'vue3-electronic-signature'
const onReplayStart = () => {
console.log('开始回放签名')
}
const onPathStart = (pathIndex: number, path: SignaturePath) => {
console.log(`开始绘制第 ${pathIndex + 1} 笔画`, path)
}
const onPathEnd = (pathIndex: number, path: SignaturePath) => {
console.log(`完成绘制第 ${pathIndex + 1} 笔画`, path)
}
const onReplayComplete = () => {
console.log('签名回放完成')
}
</script>
```
## �🎯 高级用法
### 获取和设置签名数据
```vue
<template>
<ElectronicSignature ref="signatureRef" />
<button @click="saveSignature">保存</button>
<button @click="loadSignature">加载</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SignatureMethods, SignatureData } from 'vue3-electronic-signature'
const signatureRef = ref<SignatureMethods>()
let savedData: SignatureData | null = null
const saveSignature = () => {
if (signatureRef.value) {
savedData = signatureRef.value.getSignatureData()
console.log('签名已保存', savedData)
}
}
const loadSignature = () => {
if (signatureRef.value && savedData) {
signatureRef.value.setSignatureData(savedData)
console.log('签名已加载')
}
}
</script>
```
### 导出不同格式
```typescript
// 导出PNG格式
const pngData = signatureRef.value?.save({ format: 'png' })
// 导出高质量JPEG
const jpegData = signatureRef.value?.save({
format: 'jpeg',
quality: 0.9
})
// 导出SVG矢量格式
const svgData = signatureRef.value?.save({ format: 'svg' })
// 导出指定尺寸
const resizedData = signatureRef.value?.save({
format: 'png',
size: { width: 800, height: 400 },
backgroundColor: '#ffffff'
})
```
### 工具函数使用
组件库还提供了丰富的工具函数:
```typescript
import {
getSignatureBounds,
cropSignature,
addWatermark,
convertToGrayscale
} from 'vue3-electronic-signature'
// 获取签名边界
const bounds = getSignatureBounds(signatureData)
// 裁剪签名
const croppedCanvas = cropSignature(canvas, signatureData, 10)
// 添加水印
const watermarkedCanvas = addWatermark(canvas, '© 2024 公司名称', {
position: 'bottom-right',
fontSize: 12,
opacity: 0.5
})
// 转换为灰度
const grayscaleCanvas = convertToGrayscale(canvas)
```
## 🎨 样式定制
### CSS 变量
组件支持通过CSS变量进行样式定制:
```css
.electronic-signature {
--signature-border-color: #ddd;
--signature-border-radius: 4px;
--signature-placeholder-color: #999;
--signature-toolbar-bg: #f5f5f5;
}
```
### 自定义主题
```vue
<template>
<ElectronicSignature
class="custom-signature"
:width="400"
:height="200"
/>
</template>
<style>
.custom-signature {
border: 2px solid #2196F3;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.15);
}
.custom-signature canvas {
border-radius: 10px;
}
</style>
```
## 📱 移动端优化
组件针对移动端进行了特别优化:
- 支持触摸绘制
- 防止页面滚动干扰
- 高DPI屏幕适配
- 触摸压感模拟
```vue
<template>
<!-- 移动端推荐配置 -->
<ElectronicSignature
width="100%"
:height="250"
:stroke-width="3"
:pressure-sensitive="true"
:min-stroke-width="2"
:max-stroke-width="6"
stroke-color="#2196F3"
/>
</template>
```
## 🔧 开发指南
### 本地开发
```bash
# 克隆项目
git clone https://github.com/your-username/vue3-electronic-signature.git
# 安装依赖
cd vue3-electronic-signature
npm install
# 启动开发服务器
npm run dev
# 构建组件库
npm run build:lib
```
### 项目结构
```
vue3-electronic-signature/
├── src/ # 源代码
│ ├── components/ # 组件
│ ├── types/ # 类型定义
│ ├── utils/ # 工具函数
│ └── index.ts # 入口文件
├── examples/ # 示例应用
├── dist/ # 构建输出
├── docs/ # 文档
└── tests/ # 测试文件
```
## 🤝 贡献指南
欢迎提交 Issue 和 Pull Request!
1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 开启 Pull Request
## 📄 许可证
本项目基于 [MIT](LICENSE) 许可证开源。
## 📞 支持
如果你觉得这个项目有用,请给我们一个 ⭐️!
- 📧 邮箱:852174914@qq.com
- 🐛 问题反馈:[GitHub Issues](https://github.com/wu852174914/vue3-electronic-signature/issues)
## 📝 更新日志
### v2.0.0 (最新版本)
#### 🎉 重大改进
- **删除所有断续效果** - 实现连续流畅的书写体验
- **优化优雅笔迹** - 增强由粗到细的渐变效果,删除黑色连接点
- **修复闪烁问题** - 毛笔和圆珠笔书写时的稳定渲染
- **默认笔迹调整** - 全局默认使用适中笔迹(ballpoint)
#### ✨ 笔迹样式优化
- **适中笔迹** - 连续流畅,简洁专业,商务首选(新默认)
- **优雅笔迹** - 智能渐变,由粗到细,速度感应(增强效果)
- **毛笔笔迹** - 传统书法,自然变化,稳定无闪烁
- **铅笔笔迹** - 稳定连续,简洁清晰,删除纹理效果
- **钢笔笔迹** - 极细锐利,精准线条
- **马克笔笔迹** - 超粗荧光,醒目标记
#### 🔧 技术改进
- **性能优化** - 删除复杂算法,文件大小减少至53.46kB
- **代码简化** - 移除断续效果和连接点算法
- **渲染一致性** - 实时书写与最终效果完全一致
- **回放稳定性** - 录制与回放效果完全相同
```