Vant 4 Signature 签名组件完全指南:Canvas 手写签名的实现原理与实战配置

发布时间:2026/9/13 4:55:31
Vant 4 Signature 签名组件完全指南:Canvas 手写签名的实现原理与实战配置 Vant 4 Signature 签名组件完全指南Canvas 手写签名的实现原理与实战配置【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant导读本文以 Vant 4 移动端组件库中的 Signature 签名组件为对象系统讲解其基于 Canvas 的手写签名能力从组件引入、基础用法到全部 Props / Events / 实例方法并深入源码揭示笔画绘制、高 DPI 适配、撤销历史栈、空签名检测等底层实现。读完本文你将能够在自己的 Vue 3 移动端项目中快速落地一个支持自定义笔色、线宽、背景色、撤销与确认导出的签名模块并理解其内部运行机制以便二次定制。该组件自vant 4.3.0版本起提供使用前请确认依赖版本。本文所有结论均可对照仓库源码验证主要依据 README.zh-CN.md 与 Signature.tsx。组件介绍与引入Signature 是 Vant 4 中基于 Canvas 实现的签名组件适用于电子合同签署、收货确认、审批留痕等移动端场景。它自带「清空 / 撤销 / 确认」三个操作按钮签名结果以 base64 图片字符串和原生 Canvas 元素两种形式通过submit事件对外暴露可无缝配合van-image预览或上传到服务端。注册组件组件已通过withInstall包装见 index.ts支持全量引入与按需引入两种方式并已为 Vue 全局组件声明补全类型declare module vue中注册了Signature。全局注册方式如下import { createApp } from vue; import { Signature } from vant; const app createApp(); app.use(Signature);注册完成后即可在模板中使用van-signature /。更多注册方式如按需引入、unplugin-vue-components 自动导入等请参考组件注册。代码演示基础用法组件内置「清空」「撤销」「确认」三个按钮。点击确认按钮时触发submit事件其第一个参数data包含两个字段image签名对应的图片为 base64 字符串格式若签名为空则返回空字符串可用于前端判断用户是否实际书写过签名canvas签名对应的原生 Canvas 元素。van-signature submitonSubmit clearonClear / van-image v-ifimage :srcimage /import { ref } from vue; import { showToast } from vant; export default { setup() { const image ref(); const onSubmit (data) { image.value data.image; }; const onClear () showToast(clear); return { image, onSubmit, onClear, }; }, };这是仓库 demo/index.vue 中基础用法的同构实现提交后将data.image赋给demoUrl再用van-image回显签名图片。整个签名 → 导出 → 展示的闭环由此打通。自定义颜色通过pen-color属性自定义笔触颜色默认为黑色#000van-signature pen-color#ff0000 submitonSubmit clearonClear /自定义线宽通过line-width属性自定义线条宽度默认3van-signature :line-width6 submitonSubmit clearonClear /自定义背景颜色通过background-color属性自定义画布背景颜色van-signature background-color#eee submitonSubmit clearonClear /Props 详解组件全部 Props 的声明位于 Signature.tsx均使用 Vant 统一的makeStringProp/makeNumberProp工具函数定义保证了类型安全与默认值注入。完整参数表如下参数说明类型默认值type导出图片类型stringpngpen-color笔触颜色默认黑色string#000line-width线条宽度number3history-size撤销历史记录最大数量number20background-color背景颜色string-tips当不支持 Canvas 的时候出现的提示文案string-clear-button-text清除按钮文案string清空undo-button-text撤销按钮文案string撤销confirm-button-text确认按钮文案string确认几个值得注意的细节type的取值源码 Signature.tsx 中对jpg/jpeg做了特判统一以canvas.toDataURL(image/jpeg, 0.8)的质量参数导出其他类型如默认的png则走canvas.toDataURL(image/${props.type})的通用路径。也就是说type本质上是传给toDataURL的 MIME 子类型除png、jpg/jpeg外也可尝试webp等浏览器支持的格式。三个按钮文案clearButtonText/undoButtonText/confirmButtonText的默认值并非硬编码在组件里而是通过国际化字典兜底——组件渲染时使用props.xxxButtonText || t(clear/undo/confirm)见 Signature.tsx对应文案定义在 zh-CN.ts 中clear: 清空、undo: 撤销、confirm: 确认。因此跟随ConfigProvider的语言切换这些按钮文案也会自动本地化。background-color默认值为空源码makeStringProp()说明默认不填充背景画布呈现的是 index.less 中--van-signature-content-background变量默认var(--van-background-2)对应的 CSS 背景色。Events 事件事件名说明回调参数start开始签名时触发-end结束签名时触发-signing签名过程中触发event: TouchEventsubmit点击确定按钮时触发data: { image: string; canvas: HTMLCanvasElement }clear点击取消按钮时触发-这些事件与源码中的触摸生命周期一一对应见 Signature.tsxstarttouchstart时触发。此时组件会beginPath()把lineWidth、strokeStyle设为当前pen-color并缓存画布的位置矩形canvasRect通过vant/use的useRect获取供后续坐标换算使用signingtouchmove时触发回调参数为原始TouchEvent。绘制时会先preventDefault(event)阻止页面滚动避免签名时页面跟随手指滑动并设置lineCap round、lineJoin round让笔画两端与拐角圆润随后lineTo到手指坐标并stroke()。触摸点坐标做了画布相对换算touch.clientX - canvasRect.left、touch.clientY - canvasRect.top因此组件在页面任意位置滚动布局下都能正确落笔endtouchend时触发同时会把当前画布快照压入撤销历史栈saveState()保证「上一笔」可以被精确回滚。测试用例 index.spec.ts 完整验证了这套事件链路触发touchstart后start被发射携带{ clientX: 10, clientY: 20 }触发touchmove后signing事件的touches[0]与入参一致touchend后end被发射。Slots 插槽名称说明参数tips自定义提示文案-tips插槽用于不支持 Canvas 的环境下的降级展示。源码在inBrowser时通过hasCanvasSupport()见 Signature.tsx探测创建一个临时canvas并检查getContext(2d)是否存在。若支持则渲染画布若不支持则优先渲染tips插槽内容否则渲染props.tips文本见 Signature.tsx。van-signature template #tips当前浏览器不支持 Canvas请在较新的浏览器中打开/template /van-signature对应测试 index.spec.ts 中通过 mockdocument.createElement使canvas返回空对象无getContext从而验证tips文案的正确渲染。实例方法通过 ref 可以获取到 Signature 实例并调用实例方法方法与事件无关属于命令式 API。详细说明请参考组件实例方法。方法名说明参数返回值resizev4.7.3外层元素大小或组件显示状态变化时可以调用此方法来触发重绘--clearv4.8.6可调用此方法来清除签名--submitv4.8.6触发submit事件与点击确认按钮的效果等价--undo撤销上一次笔画--这些方法通过useExpose暴露给组件实例见 Signature.tsx类型定义为 types.ts 中的SignatureExpose。各方法的内部行为undo从历史栈history中弹出最后一次快照ImageData清空画布后把栈顶即上一笔结束时的画面用putImageData还原见 Signature.tsx。历史栈由saveState维护每完成一笔就getImageData保存快照且超过history-size时从头部shift()淘汰最旧记录见 Signature.tsx。测试 index.spec.ts 验证了连续画 5 笔且historySize: 3时撤销 3 次后第 4 次撤销将不做任何事历史已耗尽clearclearRect清空画布、closePath收尾、重置历史栈为空并重新填充背景色若有最后发射clear事件submit读取当前画布先做空签名检测再按type导出 base64最终emit(submit, { image, canvas })见 Signature.tsxresize把当前画布内容getImageData取出 → 重新执行initialize()按新尺寸重建画布→putImageData还原画面实现无损重绘见 Signature.tsx。组件内部还通过watch(windowWidth, resize)监听窗口宽度变化自动重绘。空签名检测的实现细节submit中的isCanvasEmpty见 Signature.tsx是理解「空签名返回空字符串」这一行为的关键组件会创建一个同尺寸的空白画布若配置了backgroundColor则同样填充背景色然后对比canvas.toDataURL()与空白画布的toDataURL()是否相等。相等即判定签名区无任何笔迹此时image直接返回方便上层拦截「未签名即提交」的请求。类型定义组件导出以下类型定义import type { SignatureProps, SignatureInstance } from vant;SignatureProps组件 Props 的提取类型由ExtractPropTypes生成声明于 Signature.tsxSignatureInstance组件实例类型即ComponentPublicInstanceSignatureProps, SignatureExpose声明于 types.ts另有SignatureThemeVars类型对应下文主题定制中的四个 CSS 变量。SignatureInstance的典型用法import { ref } from vue; import type { SignatureInstance } from vant; const signatureRef refSignatureInstance(); signatureRef.value?.resize();结合实例方法一节你可以在签名容器尺寸变化如弹窗展开、横竖屏切换时调用resize()或在业务提交逻辑里直接调用signatureRef.value?.submit()收集签名数据实现与点击确认按钮等价的效果。主题定制样式变量组件提供了下列 CSS 变量可用于自定义样式使用方法请参考 ConfigProvider 组件。变量的声明与默认值定义在 index.less 的:root中与文档表格完全一致名称默认值描述--van-signature-paddingvar(--van-padding-xs)---van-signature-content-height200px画布高度--van-signature-content-backgroundvar(--van-background-2)画布背景色--van-signature-content-border1px dotted #dadada画布边框样式:root { --van-signature-content-height: 260px; --van-signature-content-border: 1px solid #1989fa; }样式结构上组件由__content画布容器居中布局、高度由变量控制、圆角、溢出隐藏和__footer右对齐按钮区两部分组成画布本身width/height: 100%铺满内容区按钮间距通过--van-padding-md、--van-padding-xs令牌统一控制。高 DPI 适配与绘制原理Signature 在移动端高分辨率屏下的清晰度由initialize()保证见 Signature.tsx读取window.devicePixelRatio简称 DPR非浏览器环境兜底为 1画布物理尺寸 外层容器offsetWidth / offsetHeight × dpr即按设备像素比放大调用ctx.scale(dpr, dpr)让绘图坐标系回落到 CSS 像素按需填充backgroundColor。配合 CSS 中画布width: 100%; height: 100%即 CSS 尺寸仍为容器逻辑尺寸最终呈现出「高分辨率物理画布 逻辑尺寸显示」的经典高清方案避免 Retina 屏上手写线条发虚。值得一提的边界处理initialize仅在isRenderCanvas为真浏览器且支持 Canvas时执行SSR 场景下isRenderCanvas被置为true以保持服务端渲染产物一致inBrowser ? hasCanvasSupport() : true见 Signature.tsx对应的 SSR 快照测试见 test/ssr.spec.ts。测试与质量保障组件配套了完整的测试体系test 目录除前述事件链路、撤销历史、tips 降级外还包括支持 Canvas 时正确渲染canvas元素自定义按钮文案生效confirmButtonText、clearButtonText、undoButtonTextresize/undo方法暴露且可调用窗口尺寸变化自动触发resize通过Object.defineProperty修改innerWidth后派发 resize 事件验证getImageData被调用撤销多次后清空画布、历史栈受historySize上限约束等场景。这些用例使用了rstest-canvas-mock对 Canvas 2D API 进行 mock说明组件行为在纯逻辑层面同样可被充分验证为上层业务集成提供了可靠的回归保障。结语Signature 组件以约 250 行 TSX 实现了一套完整的移动端签名解决方案触摸笔画绘制与坐标换算、DPR 高清适配、基于ImageData的撤销历史栈、空签名智能检测、Canvas 降级提示以及submit / clear / undo / resize四类命令式 API。结合本文对 Props、Events、插槽、实例方法与样式变量的逐项拆解你可以直接参照 demo/index.vue 快速集成也可以在其源码基础上按业务需要二次定制如更换按钮布局、增加签名水印、接入服务端图片上传等。【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考