Signature 手写签名
画布手写签名板:手指书写、画笔色板、撤销/清空/完成,完成导出 PNG 图片(dataURL)。支持压感笔迹(按书写速度调整线宽)、画布水印、横屏签名、导出裁剪到笔迹内容区;常与弹层组件组合用作签约弹层(组件只发 close,收起弹层由使用方决定)。
平台兼容性
| App(Android/iOS) | Web | 微信小程序 | 鸿蒙 |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
基本使用
书写后点「完成」触发 confirm,参数为 PNG dataURL(image/png 前缀),可直接用于 <image> 展示或上传:
<n-signature @confirm="onConfirm" />
function onConfirm(url: string): void {
// url 为签名图片的 dataURL
}
工具条与色板
标题、工具区、色板、各按钮默认显示,按需关闭;按钮文本可用对应 xxx-text 属性覆盖(留空用内置多语言文案):
<n-signature :show-close="false" :show-color-list="false" confirm-text="提交签名" />
压感笔迹
open-smooth 开启后按书写速度调整线宽(快则细、慢则粗);线宽范围与速度响应由四个属性调节:
<n-signature open-smooth :min-line-width="2" :max-line-width="8" :velocity-filter-weight="0.7" :min-velocity="0.25" />
水印
板面显示水印由 show-watermark 控制;导出图片是否含水印由 watermark.showOnSave 决定。single 为单个居中水印,false 为平铺(spacing 控制间距):
<n-signature show-watermark :watermark="watermark" />
const watermark: NSignatureWatermark = {
text: "仅供签约使用",
fontSize: 16,
color: "rgba(0,0,0,0.12)",
rotate: -30,
single: false,
spacing: 120,
showOnSave: false
};
横屏签名
landscape 下板面变为正方形、画布旋转 -90° 显示、触点坐标自动逆映射(书写方向与竖屏一致);横竖切换会清空已写笔迹。板面高度取容器实际宽度(正方形),height 在横屏下不生效。
<n-signature landscape />
只导出笔迹内容区
bounding-box 开启后,导出图片按全部笔迹的包围盒裁剪(含线宽余量),适合直接嵌入合同图片的场景:
<n-signature bounding-box @confirm="onConfirm" />
方法调用
通过有类型的 ref 直接调用(推荐写法):
<n-signature ref="sigRef" />
const sigRef = ref<NSignatureComponentPublicInstance | null>(null);
sigRef.value?.undo(); // 撤销一笔
sigRef.value?.clear(); // 清空全部笔迹
sigRef.value?.getImage().then((url: string): void => { // 程序化导出;空笔迹返回空串
console.log(url);
});
弹层中关闭
组件不自行消失:点关闭只发 close 事件,收起所在弹层由使用方在回调中完成:
<n-popup v-model:visible="visible">
<n-signature @close="visible = false" @confirm="onConfirm" />
</n-popup>
API
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| height | 画布板面高度,数字按 px,字符串原样(支持 px/rpx);宽度恒为容器 100% | number | string | 300 |
| pen-color | 画笔颜色(外部指定初始色/受控色;内部色板切换会更新当前色) | string | #000000 |
| pen-color-list | 画笔色板(工具条色点组,点击切换当前画笔色) | string[] | ["#000000", "#ff1e10", "#ffbe00", "#1a9bff", "#1aad19"] |
| pen-size | 固定线宽 px(open-smooth=false 时生效) | number | 2 |
| open-smooth | 是否开启压感(按书写速度调整线宽:快则细、慢则粗) | boolean | false |
| min-line-width | 压感最小线宽 px(书写最快时) | number | 2 |
| max-line-width | 压感最大线宽 px(落笔与最慢时) | number | 6 |
| velocity-filter-weight | 压感速度滤波权重(0~1,越大对速度变化响应越快) | number | 0.7 |
| min-velocity | 归一化基准速度 px/ms(低于此速度取最粗线宽) | number | 0.25 |
| background-color | 画布底色(画进画布内容,导出图片同色) | string | #ffffff |
| title | 标题文本;留空用内置文案「手写签名」(切换语言自动跟随) | string | — |
| show-title | 是否显示标题区(#title 插槽存在时整区由插槽接管) | boolean | true |
| show-toolbar | 是否显示工具区(关闭后色板与按钮一并隐藏;#toolbar 插槽存在时整区由插槽接管) | boolean | true |
| show-color-list | 是否显示画笔色板 | boolean | true |
| show-undo | 是否显示撤销按钮(无笔画时按钮呈禁用态并拦截点击) | boolean | true |
| show-clear | 是否显示清空按钮(无笔画时按钮呈禁用态并拦截点击) | boolean | true |
| show-close | 是否显示关闭按钮(点击只发 close 事件,收起所在弹层由使用方决定) | boolean | true |
| confirm-text | 完成按钮文本;留空用内置文案 | string | — |
| undo-text | 撤销按钮文本;留空用内置文案 | string | — |
| clear-text | 清空按钮文本;留空用内置文案 | string | — |
| close-text | 关闭按钮文本;留空用内置文案 | string | — |
| botton-shape | 工具区按钮形状:circle=全圆角 square=小圆角 | string | circle |
| disabled | 禁用书写(画布触摸不产笔画,组件整体降透明保留色相) | boolean | false |
| disable-scroll | 阻断画布上的页面滚动(touchmove 拦截;签名场景默认开启) | boolean | true |
| landscape | 横屏签名:板面变正方形、画布旋转 -90° 显示,触点坐标自动逆映射;横竖切换清空已写笔迹 | boolean | false |
| bounding-box | 导出图片是否只含笔迹内容区(按全部笔画包围盒裁剪,含线宽余量) | boolean | false |
| show-watermark | 是否在板面显示水印(导出图是否含水印由 watermark.showOnSave 决定) | boolean | false |
| watermark | 水印配置对象(text 必填;null 表示不启用),字段见下方 NSignatureWatermark | NSignatureWatermark | null | null |
| tips | 空签名点完成时的拦截提示文案;留空用内置文案 | string | — |
| toolbar-style | 工具区行内样式(拼接在默认布局样式之后,可覆盖间距/边框等) | string | — |
| custom-class | 根节点自定义类;类须定义在组件样式表内(页面样式打不进组件),内置示例类 n-signature--tinted(根着色) |
string | — |
| custom-style | 根节点行内样式 | string | — |
NSignatureWatermark:text(文本,必填)、fontSize(16)、fontFamily("sans-serif")、color("rgba(0,0,0,0.12)")、spacing(平铺间距 px,120)、bold(false)、rotate(角度,-30)、single(单个居中水印,false 为平铺)、showOnSave(导出图片是否含水印,false)。
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| ready | 画布就绪时触发(此后方可绘制与导出) | { width, height } 板面宽高 px |
| change | 每完成一笔(含单点)时触发 | 笔画数 |
| undo | 撤销一笔时触发(空笔迹时按钮禁用不触发) | 剩余笔画数 |
| clear | 清空笔迹时触发(空笔迹时按钮禁用不触发) | 0 |
| close | 点击关闭按钮时触发(组件不自行消失,收起所在弹层由使用方决定) | — |
| confirm | 完成签名时触发;空签名不发事件只弹提示 | PNG dataURL |
Methods
| 方法名 | 说明 | 返回 |
|---|---|---|
| clear | 清空全部笔迹(不发事件) | — |
| undo | 撤销最后一笔(空笔迹不动作) | — |
| getImage | 程序化导出签名图片(bounding-box 规则同 confirm);空笔迹返回空串、不弹提示 | Promise<string> |
Slots
| 名称 | 说明 |
|---|---|
| title | 自定义标题区(存在即整区接管,show-title 失效) |
| toolbar | 自定义工具区(存在即整区接管默认色板与按钮,show-toolbar=false 时仍不渲染) |
实现说明
- 导出通道:绘制与导出分开走——绘制用
createCanvasContextAsync成功载体上的getContext('2d'),导出用同一载体的toDataURL()(同步返回 dataURL)。画布元素上的导出 API 仅 Web 端具备,App 端必须走本通道。像素尺寸 = 板面实测 CSS 尺寸 × 屏幕像素比,2D 上下文统一按像素比缩放后以 CSS 坐标绘制(官方 hidpi 模式);画布像素尺寸赋值会重置全部画布状态,像素比缩放随之重应用。 - 矢量存档:笔迹按笔画存档(颜色 + 点列),撤销/清空/导出/尺寸变化全部矢量重绘。压感(
open-smooth)按书写速度的指数滑动平均折算线宽(快则细、慢则粗,落笔从max-line-width起);固定宽模式走中点二次贝塞尔平滑。 - 起点落定:
touchstart只记手势,画布矩形实测回调后的首个触点才落定起点——测量是异步的,先落点会从画布左上角拉出斜线并污染内容包围盒。 - 水印:矢量绘制参与重绘;
single单个居中、平铺按文本宽 +spacing步进(范围按画布对角线扩张保证旋转后全覆盖);导出时showOnSave=false临时隐去(隐 → 导 → 恢复)。 - bounding-box:导出时临时改画布像素尺寸并平移坐标全量重绘,完成后立即恢复板面尺寸重绘显示;导出图尺寸即内容包围盒(含线宽余量、不出画布边界)。单个居中水印若不在包围盒内则不出现在导出图中。
- 横屏:板面恒为正方形(高 = 容器实测宽),画布
rotate(-90deg)(正方形旋转后仍完全覆盖板面);触点按u = 宽 - 手指y、v = 手指x逆映射。横竖切换坐标系重建,清空已写笔迹(不发事件)。 - 滚动阻断:阻断绑定是编译期的——阻断分支挂
touchmove修饰符(小程序端运行时把preventDefault置空,只有 catch 绑定能阻断滚动),disable-scroll=false走裸绑定分支;翻转disable-scroll会切换分支重建画布(上下文重新初始化、笔迹矢量重绘恢复、ready再次发出)。 - 底色画进内容:
background-color直接画入画布内容(CSS 背景不进导出图),导出图片与板面观感一致。 - 多实例:画布 id 内置随机段,同页多个签名板互不冲突。
- 使用限制:组件依赖实测板面尺寸,请勿放进
display:none的容器首屏挂载(尺寸为 0 时不就绪,容器显示后自动就绪)。 - 参考源差异取舍:参考源的
enableBrush/strokeColor/strokeWidth/velocitySensitivity分别由禁用守卫、pen-color、pen-size、velocity-filter-weight承担(同义更名或能力已含);width属性不单列(块级满宽是更直接的使用者模型,height单维度控制板面);maxHistoryLength撤销历史上限不收录——本库按笔画矢量存档全量重绘,签名场景笔画数有限、撤销栈全保留(限制撤销深度反而伤害可用性,参考默认 20 的动机是旧端图像快照栈的性能);type(canvas 类型)不收录——本库渲染层仅 2d 一型;fixed(固定标题栏与工具栏的弹层形态)不收录——弹层装配归 n-popup,组件保持内嵌板面。
示例
演示工程 pkgBasic/newui/signature 页提供全属性试玩(画笔色板、压感、水印、横屏、导出裁剪等)、事件回显与实时代码。