Skip to content

Signature 手写签名 ​

画布手写签名板:手指书写、画笔色板、撤销/清空/完成,完成导出 PNG 图片(dataURL)。支持压感笔迹(按书写速度调整线宽)、画布水印、横屏签名、导出裁剪到笔迹内容区;常与弹层组件组合用作签约弹层(组件只发 close,收起弹层由使用方决定)。

平台兼容性 ​

App(Android/iOS) Web 微信小程序 鸿蒙
✓ ✓ ✓ ✓

基本使用 ​

书写后点「完成」触发 confirm,参数为 PNG dataURL(image/png 前缀),可直接用于 <image> 展示或上传:

html
<n-signature @confirm="onConfirm" />
ts
function onConfirm(url: string): void {
	// url 为签名图片的 dataURL
}

工具条与色板 ​

标题、工具区、色板、各按钮默认显示,按需关闭;按钮文本可用对应 xxx-text 属性覆盖(留空用内置多语言文案):

html
<n-signature :show-close="false" :show-color-list="false" confirm-text="提交签名" />

压感笔迹 ​

open-smooth 开启后按书写速度调整线宽(快则细、慢则粗);线宽范围与速度响应由四个属性调节:

html
<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 控制间距):

html
<n-signature show-watermark :watermark="watermark" />
ts
const watermark: NSignatureWatermark = {
	text: "仅供签约使用",
	fontSize: 16,
	color: "rgba(0,0,0,0.12)",
	rotate: -30,
	single: false,
	spacing: 120,
	showOnSave: false
};

横屏签名 ​

landscape 下板面变为正方形、画布旋转 -90° 显示、触点坐标自动逆映射(书写方向与竖屏一致);横竖切换会清空已写笔迹。板面高度取容器实际宽度(正方形),height 在横屏下不生效。

html
<n-signature landscape />

只导出笔迹内容区 ​

bounding-box 开启后,导出图片按全部笔迹的包围盒裁剪(含线宽余量),适合直接嵌入合同图片的场景:

html
<n-signature bounding-box @confirm="onConfirm" />

方法调用 ​

通过有类型的 ref 直接调用(推荐写法):

html
<n-signature ref="sigRef" />
ts
const sigRef = ref<NSignatureComponentPublicInstance | null>(null);

sigRef.value?.undo();                                  // 撤销一笔
sigRef.value?.clear();                                 // 清空全部笔迹
sigRef.value?.getImage().then((url: string): void => { // 程序化导出;空笔迹返回空串
	console.log(url);
});

弹层中关闭 ​

组件不自行消失:点关闭只发 close 事件,收起所在弹层由使用方在回调中完成:

html
<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&lt;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 页提供全属性试玩(画笔色板、压感、水印、横屏、导出裁剪等)、事件回显与实时代码。

记录 · 思考 · 创作