news 2026/9/24 16:34:56

@formily/vue 全面解析:响应式表单胶水层的架构设计、协议驱动与三种开发模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
@formily/vue 全面解析:响应式表单胶水层的架构设计、协议驱动与三种开发模式
  • 前端
  • UI组件

【免费下载链接】formily

📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3

项目地址:https://gitcode.com/gh_mirrors/fo/formily
点击查看免费下载

本指南以 @formily/vue 官方引导文档为主体,系统讲解它如何作为「渲染胶水层」将 @formily/core 的响应式 ViewModel 与 Vue 组件绑定起来,覆盖核心定位、超高性能机制、开箱即用的模型绑定、基于标准 JSON-Schema 的协议驱动,以及 Template / JSON Schema / Markup Schema 三种开发模式的完整实战代码。读完本文,你将理解 @formily/vue 的架构分层与上下文注入机制,掌握 Field 系组件的接入方式和 SchemaField 协议渲染的递归原理,并能直接在 Vue 2 / Vue 3 项目中落地三种开发模式。

核心定位:不管理数据、只做绑定的「渲染胶水层」

@formily/vue 的核心定位是将 ViewModel(即 @formily/core 创建的 Form 实例)与组件实现一个状态绑定关系。它不负责管理表单数据,不负责表单校验——这些职责全部由 @formily/core 承担,@formily/vue 仅仅是渲染胶水层(glue layer)。

但这层胶水并不「脏」:它通过标准化的绑定关系,把大量脏逻辑(组件事件转发、字段状态同步、装饰器与组件的渲染组装等)优雅解耦,从而让业务代码保持可维护。从 MVVM 角度看,@formily/core 就是 ViewModel,Component 与 Decorator 就是 View,@formily/vue 负责完成二者之间的绑定,这层绑定关系在官方概念文档中被称为「模型绑定」,具体可参见 packages/vue/docs/guide/concept.md 与 core 侧的 MVVM 指南。

在源码层面,这一绑定逻辑集中在 ReactiveField.ts:它创建并持有字段模型,把字段的value注入组件的attrs.value,并把组件的change/focus/blur事件转发给字段模型的onInput/onFocus/onBlur方法,同时根据patterneditable/disabled/readOnly/readPretty)自动设置组件的disabledreadOnly属性。整个组件被observer包裹,任何字段模型变化都会触发精确的最小化重渲染。

五大核心特性

1. 超高性能:依赖追踪、精确更新、按需渲染

借助 @formily/core 的响应式模型(packages/reactive),@formily/vue 无需额外优化即可获得高性能优势:依赖追踪、精确更新、按需渲染。字段模型之间相互独立,一个字段的输入、校验、显隐变化只会触发自身及其真正依赖它的视图更新,表单开发只需关注业务逻辑,无需考虑性能优化。

这一机制在源码中有直接体现:ReactiveField.ts 使用shallowRef持有字段实例,渲染函数通过observer(来自 @formily/reactive-vue)建立细粒度的响应式依赖,只有字段模型中被实际读取的属性变化才会触发重渲染。

2. 开箱即用:Field 系组件 + 双向绑定约定

@formily/vue 提供了一系列 Vue 组件:Field/ArrayField/ObjectField/VoidField。使用时只需给 Field 组件传入component属性(组件引用 + 属性数组),组件只要支持value/@change这样的双向绑定约定,即可快速接入,接入成本极低。例如:

<template> <FormProvider :form="form"> <Field name="input" :component="[Input, { placeholder: '请输入' }]" /> </FormProvider> </template>

component支持两种写法:单个组件引用(如:component="Input"),或[组件引用, 属性对象]的元组形式(如:component="[Input, { placeholder: '请输入' }]")。字段模型的value与组件的value自动同步,组件的@change事件自动写入字段模型。

3. 协议驱动:标准 JSON-Schema

@formily/vue 提供SchemaField这样的协议驱动组件,底层基于标准 JSON-Schema 驱动,同时扩展了x-*属性来表达 UI。这让表单开发变得动态化、可配置化,甚至可以做到一份协议,多端渲染表单(React、Vue 等不同端共享同一份 Schema 描述)。

4. 场景复用:协议片段抽象场景组件

借助协议驱动能力,可以将携带业务逻辑的协议片段抽象成场景组件,帮助用户在某些场景下高效开发,例如FormTabFormStep这类场景组件——它们本质上是对协议结构(x-componentx-content等)的封装复用。

5. 智能提示:完全 TypeScript

formily 是完全的 TypeScript 项目,用户在 VSCode 或 WebStorm 等 IDE 中开发可以获得最大化的智能提示体验,包括组件 Props 类型提示、Schema 字段提示等。packages/vue/package.json 中types字段声明了类型产物入口type-artefacts/cur/index.d.ts,并分别针对 Vue 2 / Vue 3 构建类型。

核心架构:三类上下文与统一下发

@formily/vue 的架构相比 @formily/core 并不复杂(完整架构图见 packages/vue/docs/guide/architecture.md)。它支持两类用户:

  • 纯源码开发用户:直接使用Field/ArrayField/ObjectField/VoidField组件;
  • JSON-Schema 动态开发用户:依赖SchemaField组件。

两类用户都必须使用FormProvider组件统一下发上下文;而SchemaField内部实际依赖的仍是 Field/ArrayField/ObjectField/VoidField 组件(见 RecursionField.ts 中按 Schema 的type分发到对应字段组件的逻辑)。

架构中包含三个层次的上下文,官方概念文档对此有明确说明(见 packages/vue/docs/guide/concept.md):

上下文提供者读取方式用途
表单上下文(FormContext)FormProvideruseForm读取 @formily/core 创建的 Form 实例
字段上下文(FieldContext)Field/ArrayField/ObjectField/VoidFielduseField读取当前字段模型,便于模型映射
协议上下文(FieldSchemaContext)RecursionFielduseFieldSchema读取当前字段的 Schema 描述(仅限 SchemaField / RecursionField 子树内)

在源码中,上下文通过 Vue 的 provide/inject 实现:FormProvider.ts 使用provide(FormSymbol, formRef)下发表单实例,ReactiveField.ts 使用provide(FieldSymbol, fieldRef)下发字段实例,RecursionField.ts 使用provide(SchemaSymbol, fieldSchemaRef)下发 Schema 实例。相关的 Hooks 实现位于 packages/vue/src/hooks,包括useFormuseFielduseFieldSchemauseFormEffectsuseParentForm

模型绑定:ViewModel 与 View 的桥接手段

模型绑定指将 @formily/core 的 ViewModel 与 Vue 组件(View)绑定起来的过程,主要实现手段有:

  • useField:在自定义组件中读取当前字段模型;
  • connect:连接组件与字段,支持级联应用多个 mapper;
  • mapProps:将字段模型的指定属性映射到组件 props。

connect/mapProps/mapReadPretty的实现位于 packages/vue/src/shared/connect.ts:

  • mapProps(...mappers)通过FormPath.getIn(field, extract)从字段模型中提取属性值,写入组件的目标 prop;当提取的 key 是value且映射目标不是value时,会删除原始valueprop,避免冲突。
  • mapReadPretty(component, readPrettyProps)包装组件:当field.pattern === 'readPretty'时切换为传入的只读展示组件,否则仍渲染原组件。
  • connect(target, ...mappers)依次将 mapper 应用到目标组件,最终用observer包裹为响应式组件(Vue 2 使用 functional 组件,Vue 3 使用setup返回渲染函数)。

需要注意的是:Component 只需支持value/onChange属性,即可自动实现数据层的双向绑定。ReactiveField 在渲染时会自动为组件附加value(来自字段模型)以及change/focus/blur事件处理器(内部调用field.onInput/field.onFocus/field.onBlur),这就是「开箱即用」的底层机制。

协议驱动:Schema、递归渲染与协议绑定

协议驱动渲染是 @formily/vue 中学习成本最高的部分,但掌握后收益也最高。核心包含 4 个概念:Schema、递归渲染、协议绑定、三种开发模式

Schema

formily 的协议驱动基于标准 JSON Schema,并在标准之上扩展了x-*属性来表达 UI(如x-componentx-component-propsx-decoratorx-decorator-propsx-validatorx-reactionsx-contentx-visiblex-display等),使协议具备完整描述复杂表单的能力。完整的 Schema 协议与字段模型映射关系参见 packages/vue/docs/api/shared/schema.md。

递归渲染

递归渲染是指组件 A 在某些条件下继续用组件 A 来渲染内容。由于 JSON-Schema 本身是递归型结构,RecursionField渲染时会从顶层 Schema 节点解析:非 object / array 类型直接渲染具体组件;object 类型则遍历properties,继续用 RecursionField 渲染子级 Schema 节点。以下伪代码展示了递归过程(渲染权标注在各行注释中):

{ "type": "object", "properties": { "username": { "type": "string", "x-component": "Input" }, "phone": { "type": "string", "x-component": "Input", "x-validator": "phone" }, "email": { "type": "string", "x-component": "Input", "x-validator": "email" }, "contacts": { "type": "array", "x-component": "ArrayTable", "items": { "type": "object", "properties": { "username": { "type": "string", "x-component": "Input" }, "phone": { "type": "string", "x-component": "Input", "x-validator": "phone" }, "email": { "type": "string", "x-component": "Input", "x-validator": "email" } } } } } }

@formily/vue 递归渲染的入口是SchemaField,但其内部实际使用RecursionField渲染(见 SchemaField.ts 中children.push(h(RecursionField, ...)))。特殊之处在于array 类型自增列表:由于自增列表的 UI 个性化定制程度很高,递归渲染权交给用户——需要在自定义组件(如 ArrayTable)内部手动使用 RecursionField 进行递归渲染。

SchemaFieldRecursionField的差别主要有两点(官方概念文档原述):

  • SchemaField 支持 Markup 语法,会提前解析 Markup 语法生成 JSON Schema 移交给 RecursionField 渲染;而 RecursionField 只能基于 JSON Schema 渲染;
  • SchemaField 渲染整体的 Schema 协议,RecursionField 渲染局部的 Schema 协议。

从源码看,RecursionField.ts 会根据 Schema 的type值分发:object渲染ObjectFieldarray渲染ArrayFieldvoid渲染VoidField,其余类型渲染Field;并通过onlyRenderProperties/onlyRenderSelf/mapProperties/filterProperties等 props 控制递归渲染的范围与转换。

协议绑定

协议绑定是将 Schema 协议转换成模型绑定的过程。JSON-Schema 是 JSON 字符串、可离线存储,而模型绑定是内存间的运行时(Runtime)绑定关系。例如x-component在 Schema 中是组件的字符串标识,在字段模型中则是组件引用,因此 JSON 字符串与 Runtime 层需要转换。RecursionField 中通过schema.toFieldProps({ ...options, scope })(见 RecursionField.ts 的getPropsFromSchema)完成「Schema → 字段模型属性」的转换,options.components中的组件注册表则完成「字符串标识 → 组件引用」的解析(ReactiveField 渲染时用FormPath.getIn(options?.components, field.componentType)查找组件)。

总结:@formily/vue 中存在2 层绑定关系——Schema 绑定模型、模型绑定组件,实现绑定的胶水层就是 @formily/vue。需要注意,Schema 绑定字段模型之后,字段模型感知不到 Schema:例如要修改enum,实际是修改字段模型中的dataSource属性。字段模型的操作方式参考 core 的 Field 模型文档。

三种开发模式实战

@formily/vue 面向不同用户提供三种开发模式,完整对比与示例见 packages/vue/docs/guide/concept.md。

Template 开发模式

该模式主要使用Field/ArrayField/ObjectField/VoidField组件,适合纯源码开发:

<template> <FormProvider :form="form"> <Field name="input" :component="[Input, { placeholder: '请输入' }]" /> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/vue' import 'ant-design-vue/dist/antd.css' export default { components: { FormProvider, Field }, data() { return { Input, form: createForm(), } }, } </script>

createForm()来自 @formily/core,返回的 Form 实例是表单唯一的 ViewModel;FormProvider负责将其下发给所有子组件。

JSON Schema 开发模式

该模式将 JSON Schema 直接传给SchemaFieldschema属性,Schema 可以是离线存储、动态下发的数据,适合可配置化 / 低代码场景:

<template> <FormProvider :form="form"> <SchemaField :schema="schema" /> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/vue' import 'ant-design-vue/dist/antd.css' const { SchemaField } = createSchemaField({ components: { Input, }, }) export default { components: { FormProvider, SchemaField }, data() { return { form: createForm(), schema: { type: 'object', properties: { input: { type: 'string', 'x-component': 'Input', 'x-component-props': { placeholder: '请输入', }, }, }, }, } }, } </script>

注意:createSchemaField({ components })工厂函数负责注册协议中用到的组件映射(字符串x-component标识 → 实际组件),返回的SchemaField才能正确解析协议。源码见 SchemaField.ts,组件注册表会与SchemaFieldcomponentsprop 合并(options.componentsprops.components合并后下发)。

Markup Schema 开发模式

该模式是对源码开发更友好的 Schema 开发模式,同样使用 SchemaField 相关组件。主要有以下特点:

  • 主要依赖SchemaStringField/SchemaArrayField/SchemaObjectField等描述标签来表达 Schema;
  • 每个描述标签都代表一个 Schema 节点,与 JSON-Schema 等价;
  • SchemaField 子节点不能随意插入 UI 元素——SchemaField 只会解析子节点的所有 Schema 描述标签并转换成 JSON Schema,最终交给 RecursionField 渲染;如需插入 UI 元素,可在SchemaVoidField上使用x-content属性。
<template> <FormProvider :form="form"> <SchemaField> <SchemaStringField x-component="Input" :x-component-props="{ placeholder: '请输入' }" /> <div>我不会被渲染</div> <SchemaVoidField x-content="我会被渲染" /> <SchemaVoidField :x-content="Comp" /> </SchemaField> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/vue' import 'ant-design-vue/dist/antd.css' const SchemaComponents = createSchemaField({ components: { Input, }, }) const Comp = { render(h) { return h('div', ['我也会被渲染']) }, } export default { components: { FormProvider, ...SchemaComponents }, data() { return { form: createForm(), Comp, } }, } </script>

从源码看,createSchemaField会额外生成SchemaStringFieldSchemaObjectFieldSchemaArrayFieldSchemaBooleanFieldSchemaDateFieldSchemaDateTimeFieldSchemaVoidFieldSchemaNumberField等标记组件(见 SchemaField.ts 的SchemaFieldFactory),它们统一包装内部的MarkupField:把标签上的属性解析为 Schema 节点,添加到父级 Schema 的properties(object/void 类型)或items(array 类型)中,最终整个 Markup 结构被转换为一份 JSON Schema 交给 RecursionField 渲染。x-*系列属性(如x-componentx-decoratorx-validatorx-reactionsx-visiblex-disabledx-read-pretty等)以及标准 JSON-Schema 关键字(enumpatternmaximumrequired等)都作为标记组件的 props 被解析。

安装与快速开始

@formily/vue通过vue-demi同时兼容 Vue 2 与 Vue 3(peerDependencies 声明vue: ^2.6.0 || >=3.0.0-rc.0,见 packages/vue/package.json),官方安装命令如下:

Vue 3:

$ npm install --save @formily/core @formily/vue

Vue 2(额外需要@vue/composition-api):

$ npm install --save @formily/core @formily/vue @vue/composition-api

安装后即可按上文三种开发模式任一方式快速开始。完整可运行的入门 Demo 位于 packages/vue/docs/demos/index.vue,各 API 组件的独立示例分布在 packages/vue/docs/demos/api 目录(对应fieldschema-fieldarray-fieldobject-fieldvoid-fieldform-providerform-consumerrecursion-fieldconnectmap-props等)。官方 API 文档入口见 packages/vue/docs/api,共覆盖 11 个组件、5 个 Hooks 与 6 个共享工具(connect、mapProps、mapReadPretty、observer、schema、injections)。

状态可观测:对接 Formily DevTools

安装 FormilyDevtools 扩展可以实时观测模型状态变化、排查问题。本仓库中的 DevTools 源码位于 devtools/chrome-extension,其通过 content script 与后台脚本注入、页面内inject.ts通信,读取表单与字段模型的响应式状态树(见 devtools/chrome-extension/src/extension/inject.ts 与 devtools/chrome-extension/src/extension/backend.ts)。配合 @formily/vue 的observer精确渲染机制,DevTools 可以实时展示字段的值、校验状态、显隐状态与依赖关系,帮助开发者快速定位复杂联动场景下的问题。

小结

@formily/vue 的设计哲学是「职责分离」:把数据、校验、联动交给 @formily/core 的响应式模型,把自己定位为纯粹的渲染胶水层,通过 FormProvider 统一上下文、Field 系组件完成模型绑定、SchemaField/RecursionField 完成协议驱动。理解三类上下文、两层绑定关系与三种开发模式,即可在 Vue 项目中按需选择最合适的表单开发方式——无论是追求零成本的 Template 模式、面向动态化的 JSON Schema 模式,还是兼顾源码友好与协议能力的 Markup Schema 模式。

  • 前端
  • UI组件

【免费下载链接】formily

📱🚀 🧩 Cross Device & High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3

项目地址:https://gitcode.com/gh_mirrors/fo/formily
点击查看免费下载
上一篇:Mac版Navicat无限试用终极指南:三种简单方法免费使用Navicat Premium
下一篇:3DSident如何彻底改变3DS系统检测体验?深度解析CIA架构的技术革命

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 16:34:14

AI用88小时解开90年难题,人类只讨论了14天

2026年9月8日&#xff0c;OpenAI 发布声明说&#xff0c;他们的一个内部模型解开了纳维-斯托克斯问题&#xff0c;一道数学界悬了90多年的题。一万多个AI智能体&#xff0c;88小时&#xff0c;165页论文。就在这个声明公布的两分钟前&#xff0c;一位澳大利亚数学家在自己的社交…

作者头像 李华
网站建设 2026/9/24 16:32:43

EmDash Seed 文件完全指南:从 Schema 定义到数据导出的实战手册

EmDash Seed 文件完全指南&#xff1a;从 Schema 定义到数据导出的实战手册 【免费下载链接】emdash EmDash is a full-stack TypeScript CMS based on Astro; the spiritual successor to WordPress 项目地址: https://gitcode.com/gh_mirrors/emdas/emdash seed 文件&…

作者头像 李华
网站建设 2026/9/24 16:32:15

热门题目分类+清单

题单来源&#xff1a;https://leetcode.cn/studyplan/top-100-liked/ 类别题目解题思路哈希表1.两数之和&#xff08;简单&#xff09;49.字母异位词分组&#xff08;中等&#xff09;128.最长连续序列&#xff08;中等&#xff09;①以每个item为开端且item-1不在set里面&…

作者头像 李华