Vant Signature 签名组件实战指南:基于 Canvas 的手写签名、撤销与导出 Vant Signature 签名组件实战指南基于 Canvas 的手写签名、撤销与导出【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant导读Signature是 Vant 移动端组件库中用于电子签名场景的组件底层基于 HTML5 Canvas 实现支持手写笔迹、实时导出 base64 图片、多步撤销以及主题定制。本指南以 packages/vant/src/signature/README.md 为主体结合组件源码、样式文件与测试用例系统讲解组件的安装引入、基础用法、全部 Props/Events/Methods/Slots 参数、类型定义与 CSS 变量主题定制并深入到 Canvas 绘制、撤销历史栈等底层实现原理帮助你完整掌握在 Vue 3 移动端项目中落地签名能力的方案。适用前提本组件要求vant版本 4.3.0且基于 Vue 3 Vite 等现代构建环境。组件概述与适用场景Signature是专为签名场景设计的组件核心特点基于 Canvas 实现所有笔迹绘制都发生在canvas上不依赖第三方绘图库组件体积小开箱即用的操作栏自带「清空 / 撤销 / 确认」三个按钮内部复用 Vant 的Button组件数据出口统一点击确认后通过submit事件一次性输出{ image, canvas }方便后续上传、存储或与后端签署流程对接历史记录管理内置撤销历史栈支持最多history-size步的撤销操作。从源码结构看Signature.tsx组件由签名画布区__content和操作按钮区__footer两部分渲染组成非常适合合同签署、确认书、收货签收、登记表确认等移动端表单场景。安装与引入通过 npm 安装npm i vant注册组件支持全局注册与按需引入两种方式。全局注册需要先通过createApp创建应用实例import { createApp } from vue; import { Signature } from vant; const app createApp(); app.use(Signature);在模板中直接以van-signature使用van-signature /从源码看组件通过withInstall包装导出index.ts同时该文件为 Vue 的GlobalComponents声明了Signature全局组件类型因此在 TypeScript Volar 环境下使用van-signature时可获得完整的类型提示。更多注册方式如按需引入、unplugin-vue-components自动导入可参考 组件注册文档。基础用法核心事件流submit 与 clear组件的事件模型非常简单清晰。当用户点击确认按钮时组件触发submit事件回调的第一个参数data包含两个字段字段类型说明imagestring签名对应的图片base64 字符串格式若签名为空则返回空字符串canvasHTMLCanvasElement当前绘制用的 Canvas 元素当点击清空按钮时组件触发clear事件无参数。基础用法示例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, }; }, };拿到data.image后既可以直接赋值给 Vant 的Image组件预览也可以提交给后端保存。上述完整写法与仓库内 demo/index.vue 中的基础用法示例一致。空签名处理值得注意的一个细节当画布为空时点击确认submit事件中的image字段是空字符串而非data:image/png;base64,...形式的空图。这一点在实际业务中非常实用——你不需要额外校验签名是否为空。从源码看Signature.tsx组件通过isCanvasEmpty方法创建一张与当前画布同尺寸的空白对照 Canvas若设置了background-color则用同色填充后对比再通过canvas.toDataURL()与当前画布数据比对完全一致即判定为空。这也意味着纯色背景填充不会影响空签名判定。自定义笔触与背景笔触颜色pen-color通过pen-color属性设置笔迹颜色默认黑色van-signature pen-color#ff0000 submitonSubmit clearonClear /线条宽度line-width通过line-width属性设置线条宽度数值类型默认3van-signature :line-width6 submitonSubmit clearonClear /背景颜色background-color通过background-color属性设置签名区背景色默认透明无背景色van-signature background-color#eee submitonSubmit clearonClear /源码实现上背景色通过fillRect在整个画布上填充Signature.tsx并在初始化、清空、撤销回退时都会被重新填充保证任意操作后背景色保持一致。导出图片类型typetype属性控制导出图片的 MIME 类型默认png。源码中对jpg与jpeg做了特殊处理使用canvas.toDataURL(image/jpeg, 0.8)以 80% 质量压缩导出其余类型如webp则走通用分支canvas.toDataURL(image/${type})Signature.tsx。需要更小体积的图片时如用于上传可以指定typejpg。Props 完整参数表以下为组件全部 Props对应 Signature.tsx 中signatureProps的定义参数说明类型默认值type导出图片类型stringpngpen-color笔触颜色默认黑色string#000line-width线条宽度number3history-size撤销历史记录最大数量number20background-color背景颜色string-tips当不支持 Canvas 时出现的提示文案string-clear-button-text清空按钮文案string清空英文Clearundo-button-text撤销按钮文案string撤销英文Undoconfirm-button-text确认按钮文案string确认英文Confirm补充说明pen-color、line-width等属性在每次笔画开始时touchStart被重新写入 Canvas 2D 上下文strokeStyle、lineWidth所以运行中动态修改也会在下一笔生效三个按钮文案属性均为String类型默认值为空时组件会回退到内置多语言文案源码中为props.clearButtonText || t(clear)形式即跟随组件库语言包history-size控制撤销历史栈的最大容量超出时最早的记录会被丢弃详见下文「撤销实现原理」tips用于 Canvas 不可用的兜底提示。源码通过hasCanvasSupport检测document.createElement(canvas).getContext(2d)是否存在Signature.tsx检测失败时渲染区会替换为提示文本tips属性或tips插槽而不是报错。Events 事件事件名说明回调参数start开始签名时触发手指/触摸落下-end结束签名时触发手指抬起-signing签名过程中触发event: TouchEventsubmit点击确认按钮时触发data: { image: string; canvas: HTMLCanvasElement }clear点击清空按钮时触发-源码将事件绑定在 Canvas 的touchstart/touchmove/touchend上Signature.tsx并透传了原生TouchEvent因此signing事件可用于实时获取触点坐标等场景。绘制过程中调用了preventDefault阻止默认行为如页面滚动跟随保证书写体验。Slots 插槽名称说明插槽参数tips自定义提示文案Canvas 不可用时的兜底展示-当浏览器不支持 Canvas 时若提供了tips插槽则渲染插槽内容否则渲染tips属性文本。测试用例should render tips correctlytest/index.spec.ts通过 mockdocument.createElement验证了该兜底分支的渲染结果。实例方法Methods通过ref可以获取 Signature 实例并调用实例方法组件通过useExpose将方法挂载到组件实例代理上use-expose.ts方法名说明参数返回值resizev4.7.3外层元素大小或组件显示状态变化时调用触发重绘--clearv4.8.6清除签名--submitv4.8.6触发submit事件与点击确认按钮效果等价--undo撤销上一次笔画--典型用法在表单提交前主动调用submit获取签名数据无需用户手动点击确认按钮van-signature refsignatureRef submitonSubmit /import { ref } from vue; const signatureRef ref(); // 需要提交时 signatureRef.value?.submit();关于resize源码通过watch(windowWidth, resize)监听窗口宽度变化自动触发重绘Signature.tsx同时在初始化时根据devicePixelRatio对画布做高清屏适配canvas.width offsetWidth * dpr并ctx.scale(dpr, dpr)见 Signature.tsx。当容器尺寸因布局变化而改变如从隐藏切换为显示、旋转屏幕时可手动调用resize()保留原有笔迹并重绘。测试用例should call resize when window width changestest/index.spec.ts验证了窗口 resize 时会触发getImageData重绘逻辑。类型定义组件导出以下类型定义import type { SignatureProps, SignatureInstance } from vant;SignaturePropsProps 对应的类型由ExtractPropTypestypeof signatureProps推导Signature.tsxSignatureInstance组件实例类型包含resize、clear、submit、undo四个公开方法types.ts。SignatureInstance用法示例import { ref } from vue; import type { SignatureInstance } from vant; const signatureRef refSignatureInstance(); signatureRef.value?.resize();此外还导出了SignatureThemeVars类型signaturePadding、signatureContentHeight、signatureContentBackground、signatureContentBorder用于类型安全的主题变量定制types.ts。撤销与历史栈的底层原理undo与history-size的实现是 Signature 组件最具技术含量的部分值得深入理解入栈时机每次touchend一笔结束时调用saveState将当前画布内容通过getImageData(0, 0, canvasWidth, canvasHeight)快照存入history数组Signature.tsx容量上限history长度达到history-size时最早的历史快照通过shift()丢弃即只保留最近 N 步撤销动作undo弹出栈顶快照后先clearRect清空画布并重新填充背景色再将栈顶上一笔结束时的状态通过putImageData恢复Signature.tsx当历史耗尽时画布被完全清空清空重置clear在清空画布的同时也会将整个history数组重置为空。测试用例完整验证了这一机制undo should restore canvas to previous statetest/index.spec.ts绘制两笔后撤销一次断言putImageData被调用恢复第一笔状态再撤销一次则仅执行clearRect历史耗尽history should be limited by historySize proptest/index.spec.ts在historySize: 3下绘制 5 笔撤销 3 次后第 4 次撤销不再触发putImageData精确验证了容量上限与丢弃策略。这些测试同时也是理解组件行为契约的最佳参考支持的撤销步数 min(已绘制笔画数, history-size)。主题定制CSS 变量组件提供以下 CSS 变量用于自定义样式推荐通过 ConfigProvider 组件 进行全局或局部主题定制名称默认值描述--van-signature-paddingvar(--van-padding-xs)组件内边距--van-signature-content-height200px画布高度--van-signature-content-backgroundvar(--van-background-2)画布背景色--van-signature-content-border1px dotted #dadada画布边框样式这些变量的定义与使用位置见 index.less变量在:root, :host作用域声明便于在自定义元素/全局环境生效签名区域.van-signature__content使用flex居中布局画布canvas的宽高被设置为100%以填满内容区因此修改--van-signature-content-height即可直观改变书写区域高度内容区同时带border-radius: var(--van-radius-lg)圆角与overflow: hidden保证背景填充不溢出圆角底部操作栏.van-signature__footer右对齐排布按钮间通过margin-left分隔。例如想将签名区域高度调整为 300px 并改为实线边框// 通过 ConfigProvider 局部覆盖 import { ref } from vue; const themeVars ref({ signatureContentHeight: 300px, signatureContentBorder: 1px solid #666, });van-config-provider :theme-varsthemeVars van-signature / /van-config-provider完整实战示例签署确认表单结合以上内容给出一个贴近真实业务如收货签收的完整示例用户签名后立即预览同时自动提交给后端template van-config-provider :theme-varsthemeVars van-signature refsignatureRef pen-color#333 :line-width4 background-color#fff :history-size10 confirm-button-text提交签名 submitonSubmit clearonClear / /van-config-provider van-image v-ifpreview :srcpreview width100% / /template script setup import { ref } from vue; import { showToast } from vant; import type { SignatureInstance } from vant; const signatureRef refSignatureInstance(); const preview ref(); const themeVars { signatureContentHeight: 240px, }; const onSubmit ({ image, canvas }) { if (!image) { showToast(请先签名); return; } preview.value image; // 此处可将 base64 图片上传到服务端 console.log(canvas:, canvas); }; const onClear () { preview.value ; showToast(已清空); }; /script在该示例中空签名提交会被!image拦截submit事件同时携带了 base64 图片与 Canvas 元素便于需要原始 Canvas 做进一步处理如追加水印的场景resize()可在容器尺寸变化时调用以保持画布内容。总结Vant 的Signature组件用约两百行核心代码Signature.tsx完整实现了移动端签名场景的关键能力Canvas 高清屏适配与绘制、空签名智能判定、多步撤销历史栈、按钮文案本地化与 CSS 变量主题定制。接入时只需关注三件事通过submit事件接收{ image, canvas }数据、用history-size控制撤销深度、必要时通过resize()响应容器尺寸变化。相关演示与测试分别位于 demo/index.vue 与 test/index.spec.ts可作为二次开发的直接参考。【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考