TanStack Form Vue 快速上手:从零构建一个带同步/异步校验的 Simple 表单示例

📅 发布时间:2026/9/17 10:08:10
TanStack Form Vue 快速上手:从零构建一个带同步/异步校验的 Simple 表单示例
TanStack Form Vue 快速上手从零构建一个带同步/异步校验的 Simple 表单示例【免费下载链接】form Headless, performant, and type-safe form state management for TS/JS, React, Vue, Angular, Solid, and Lit.项目地址: https://gitcode.com/GitHub_Trending/form/form导读本文基于仓库中的 Vue 最小示例 examples/vue/simple完整还原一个仅需useForm与form.Field两个核心 API 即可驱动的 Headless 表单包含双向数据绑定、同步与异步校验、输入防抖、错误信息展示以及提交状态控制。读完本文你将掌握 TanStack Vue Form 的最小可用范式并了解其底层如何依托tanstack/form-core的FormApi/FieldApi与tanstack/vue-store实现响应式状态管理从而能够快速迁移到大型、复杂表单场景。示例概览这个 Simple 示例包含什么本示例是 TanStack Form 为 Vue 3 提供的最小完整案例目标只有一个form元素内两个输入框firstName、lastName和一个提交按钮。它的目录结构如下均为仓库根目录下的相对路径examples/vue/simple/README.md示例运行说明本文主体来源examples/vue/simple/src/App.vue表单主组件包含全部表单逻辑与模板examples/vue/simple/src/FieldInfo.vue字段错误信息与校验状态展示子组件examples/vue/simple/src/main.ts应用入口examples/vue/simple/package.json依赖与脚本定义examples/vue/simple/vite.config.tsVite 构建配置。尽管是Simple示例它已经覆盖了 TanStack Form 的核心闭环表单状态创建 → 字段注册与绑定 → 校验同步 异步→ 错误展示 → 提交是理解后续array、multi-step-wizard、standard-schema等 Vue 示例的基础。环境准备与运行方式按 examples/vue/simple/README.md 的说明安装依赖与启动开发服务器只需两条命令任选你习惯的包管理器npm install npm run dev或使用yarn/pnpmyarn # 或 pnpm i yarn dev # 或 pnpm devexamples/vue/simple/package.json 中的脚本与依赖决定了该示例的运行环境{ scripts: { dev: vite, build: vite build, build:dev: vite build -m development, test:types: vue-tsc, serve: vite preview }, dependencies: { tanstack/vue-form: ^1.33.5, vue: ^3.5.13 }, devDependencies: { vitejs/plugin-vue: ^5.2.4, typescript: 5.9.3, vite: ^7.2.2, vue-tsc: ^2.2.2 } }几点实操提示项目使用 Vite vitejs/plugin-vue构建vue-tsc用于类型检查npm run test:types说明示例默认强类型约束examples/vue/simple/vite.config.ts 中optimizeDeps.exclude: [tanstack/vue-form]将 TanStack Vue Form 排除出依赖预构建避免本地开发时出现重复实例化问题这是官方示例刻意为之的配置入口 examples/vue/simple/src/main.ts 与普通 Vue 3 应用无异直接createApp(App).mount(#app)挂载点定义在 examples/vue/simple/index.html 的div idapp。核心实现一useForm 创建表单状态整个表单的逻辑起点在 examples/vue/simple/src/App.vue 的script setup langts中import { useForm } from tanstack/vue-form import FieldInfo from ./FieldInfo.vue const form useForm({ defaultValues: { firstName: , lastName: , }, onSubmit: async ({ value }) { // Do something with form data alert(JSON.stringify(value)) }, })要点拆解useForm返回一个响应式的form实例它在模板中同时承担组件form.Field、form.Subscribe与状态源form.handleSubmit等的双重职责defaultValues声明表单初始值firstName、lastName的类型会被自动推导后续字段的name与value均受 TypeScript 严格约束onSubmit接收{ value }其中value是当前完整表单数据示例中通过alert(JSON.stringify(value))演示拿到表单数据后做什么。从源码看useForm内部packages/vue-form/src/useForm.tsx实际上是tanstack/form-core中FormApi的 Vue 适配层核心状态与校验逻辑全部由FormApi管理Vue 侧通过tanstack/vue-store的useSelector建立响应式订阅再以defineComponent包装出Field、FieldGroup、Subscribe等子组件。这意味着你在 Vue 里写下的配置项如defaultValues、onSubmit、各生命周期校验函数与 React/Solid/Angular 等框架共用同一套核心实现心智模型可以平滑迁移。核心实现二form.Field 注册字段与数据绑定字段绑定采用渲染插槽模式form.Field是一个由form派生的组件通过name声明字段路径通过作用域插槽向模板暴露field与state两个对象form.Field namefirstName :validators{ ... } template v-slot{ field, state } label :htmlForfield.nameFirst Name:/label input :idfield.name :namefield.name :valuefield.state.value input (e) field.handleChange((e.target as HTMLInputElement).value) blurfield.handleBlur / FieldInfo :statestate / /template /form.Field这里体现的是 TanStack Form 的Headless 设计它不渲染任何输入组件只提供状态与动作field.name字段名field.state.value字段当前值受控输入的数据源field.handleChange(value)更新字段值触发onChange系列校验field.handleBlur()标记字段失焦触发onBlur系列校验并置isTouched为truestate字段当前完整状态快照含value、meta等可直接传给子组件。lastName字段的写法完全一致但不带任何校验器用来对比有校验/无校验字段的行为差异。从源码结构看packages/vue-form/src/useField.tsxField组件底层由FieldApi驱动其泛型约束TName extends DeepKeysTParentData与TData extends DeepValueTParentData, TName保证了name必须是defaultValues中真实存在的路径、值类型也必须匹配——这就是类型安全在字段层面的体现。核心实现三同步与异步校验组合firstName字段演示了 TanStack Form 最有代表性的校验体系——同步 异步 防抖叠加:validators{ onChange: ({ value }) !value ? A first name is required : value.length 3 ? First name must be at least 3 characters : undefined, onChangeAsyncDebounceMs: 500, onChangeAsync: onChangeFirstName, }对应的异步校验函数在script setup中定义async function onChangeFirstName({ value }: { value: string }) { await new Promise((resolve) setTimeout(resolve, 1000)) return value.includes(error) No error allowed in first name }三层校验的含义分别是配置项触发时机行为说明onChange每次handleChange同步校验空值报A first name is required长度小于 3 报First name must be at least 3 characters通过则返回undefined无错误onChangeAsyncDebounceMs: 500值变更后500ms 防抖避免每次输入都发起异步校验onChangeAsync防抖窗口结束后异步校验模拟 1 秒网络延迟若值中包含error子串则返回No error allowed in first name这套设计对应tanstack/form-core中ValidationLogic.ts的校验调度机制同步校验函数的结果会被立即合并进字段meta.errors异步校验则经过防抖后执行执行期间meta.isValidating置为true供 UI 显示Validating...状态。校验函数返回undefined表示通过返回字符串或字符串数组表示错误信息返回false表示格式非法但不提供具体消息——理解这个约定后写自定义校验器就非常简单。核心实现四FieldInfo 错误展示组件examples/vue/simple/src/FieldInfo.vue 把错误展示抽成了可复用组件script setup langts import { AnyFieldApi } from tanstack/vue-form const props defineProps{ state: AnyFieldApi[state] }() /script template template v-ifprops.state.meta.isTouched em v-forerror of props.state.meta.errors{{ error }}/em {{ props.state.meta.isValidating ? Validating... : null }} /template /template关键点state.meta.isTouched字段是否被触碰过失焦过。示例特意触碰后才展示错误避免用户还没开始输入就满屏红色提示的糟糕体验state.meta.errors当前字段的错误信息数组同步与异步校验的结果都会归并到这里v-for可渲染多条错误state.meta.isValidating是否有异步校验正在进行示例用它渲染Validating...占位文案类型AnyFieldApi[state]由tanstack/vue-form导出表示任意字段的状态类型保证该组件可被任意字段复用。核心实现五form.Subscribe 控制提交按钮提交按钮的可点击/禁用与提交中状态由form.Subscribe订阅表单级状态得到form.Subscribe template v-slot{ canSubmit, isSubmitting } button typesubmit :disabled!canSubmit {{ isSubmitting ? ... : Submit }} /button /template /form.SubscribecanSubmit表单是否允许提交所有字段校验通过且未处于提交中时为trueisSubmittingonSubmit异步执行期间为true此时按钮文案显示...且被禁用防止重复提交。表单的form标签通过原生submit事件拦截默认行为后调用form.handleSubmit()form submit (e) { e.preventDefault() e.stopPropagation() form.handleSubmit() } handleSubmit会先跑完字段/表单的onSubmit相关校验全部通过后调用你传入的onSubmit回调示例中onSubmit是async函数因此isSubmitting会持续到alert被关闭为止。从 Simple 到复杂这个示例揭示的架构规律虽然示例只有两个输入框但它已经完整展现了 TanStack Form 在 Vue 生态中的三条架构规律结合 packages/vue-form/src/useForm.tsx、packages/vue-form/src/useField.tsx 源码可以印证核心无关框架校验逻辑、状态机、深路径类型推导都沉淀在tanstack/form-core的FormApi/FieldApi见 packages/form-core/src/FormApi.ts、packages/form-core/src/FieldApi.tsVue 适配层只负责把核心状态桥接成响应式数据响应式靠 storeVue 侧通过tanstack/vue-store的useSelector做细粒度订阅所以字段级状态变化不会导致整棵组件树重渲染这也是大表单性能的基石Headless 渲染form.Field、form.Subscribe只暴露field/state输入控件、样式、布局完全由你掌控天然适配任意 UI 组件库Element Plus、Naive UI 等仓库中另有 examples/vue 下的array、multi-step-wizard、standard-schema等示例可进一步参考。小结通过 examples/vue/simple 这一个最小示例你已掌握 TanStack Vue Form 的五个核心动作useForm创建表单、form.Field注册字段、validators配置同步/异步/防抖校验、FieldInfo式组件展示错误、form.Subscribe驱动提交按钮。在此基础上将两个字段扩展到任意数量、把onSubmit的alert换成真实的 API 请求就是一个可投入生产的 Vue 表单页——后续进阶示例多步向导、数组字段、Standard Schema 校验都可以视为这套最小范式的组合与延伸。【免费下载链接】form Headless, performant, and type-safe form state management for TS/JS, React, Vue, Angular, Solid, and Lit.项目地址: https://gitcode.com/GitHub_Trending/form/form创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考