ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

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

@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 就是 ViewModelComponent 与 Decorator 就是 Viewformily/vue 负责完成二者之间的绑定这层绑定关系在官方概念文档中被称为「模型绑定」具体可参见 packages/vue/docs/guide/concept.md 与 core 侧的 MVVM 指南。在源码层面这一绑定逻辑集中在 ReactiveField.ts它创建并持有字段模型把字段的value注入组件的attrs.value并把组件的change/focus/blur事件转发给字段模型的onInput/onFocus/onBlur方法同时根据patterneditable/disabled/readOnly/readPretty自动设置组件的disabled与readOnly属性。整个组件被observer包裹任何字段模型变化都会触发精确的最小化重渲染。五大核心特性1. 超高性能依赖追踪、精确更新、按需渲染借助 formily/core 的响应式模型packages/reactiveformily/vue 无需额外优化即可获得高性能优势依赖追踪、精确更新、按需渲染。字段模型之间相互独立一个字段的输入、校验、显隐变化只会触发自身及其真正依赖它的视图更新表单开发只需关注业务逻辑无需考虑性能优化。这一机制在源码中有直接体现ReactiveField.ts 使用shallowRef持有字段实例渲染函数通过observer来自 formily/reactive-vue建立细粒度的响应式依赖只有字段模型中被实际读取的属性变化才会触发重渲染。2. 开箱即用Field 系组件 双向绑定约定formily/vue 提供了一系列 Vue 组件Field/ArrayField/ObjectField/VoidField。使用时只需给 Field 组件传入component属性组件引用 属性数组组件只要支持value/change这样的双向绑定约定即可快速接入接入成本极低。例如template FormProvider :formform Field nameinput :component[Input, { placeholder: 请输入 }] / /FormProvider /templatecomponent支持两种写法单个组件引用如:componentInput或[组件引用, 属性对象]的元组形式如:component[Input, { placeholder: 请输入 }]。字段模型的value与组件的value自动同步组件的change事件自动写入字段模型。3. 协议驱动标准 JSON-Schemaformily/vue 提供SchemaField这样的协议驱动组件底层基于标准 JSON-Schema 驱动同时扩展了x-*属性来表达 UI。这让表单开发变得动态化、可配置化甚至可以做到一份协议多端渲染表单React、Vue 等不同端共享同一份 Schema 描述。4. 场景复用协议片段抽象场景组件借助协议驱动能力可以将携带业务逻辑的协议片段抽象成场景组件帮助用户在某些场景下高效开发例如FormTab、FormStep这类场景组件——它们本质上是对协议结构x-component与x-content等的封装复用。5. 智能提示完全 TypeScriptformily 是完全的 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上下文提供者读取方式用途表单上下文FormContextFormProvideruseForm读取 formily/core 创建的 Form 实例字段上下文FieldContextField/ArrayField/ObjectField/VoidFielduseField读取当前字段模型便于模型映射协议上下文FieldSchemaContextRecursionFielduseFieldSchema读取当前字段的 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包括useForm、useField、useFieldSchema、useFormEffects、useParentForm。模型绑定ViewModel 与 View 的桥接手段模型绑定指将 formily/core 的 ViewModel 与 Vue 组件View绑定起来的过程主要实现手段有useField在自定义组件中读取当前字段模型connect连接组件与字段支持级联应用多个 mappermapProps将字段模型的指定属性映射到组件 props。connect/mapProps/mapReadPretty的实现位于 packages/vue/src/shared/connect.tsmapProps(...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、递归渲染、协议绑定、三种开发模式。Schemaformily 的协议驱动基于标准 JSON Schema并在标准之上扩展了x-*属性来表达 UI如x-component、x-component-props、x-decorator、x-decorator-props、x-validator、x-reactions、x-content、x-visible、x-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 进行递归渲染。SchemaField与RecursionField的差别主要有两点官方概念文档原述SchemaField 支持 Markup 语法会提前解析 Markup 语法生成 JSON Schema 移交给 RecursionField 渲染而 RecursionField 只能基于 JSON Schema 渲染SchemaField 渲染整体的 Schema 协议RecursionField 渲染局部的 Schema 协议。从源码看RecursionField.ts 会根据 Schema 的type值分发object渲染ObjectField、array渲染ArrayField、void渲染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 :formform Field nameinput :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(), } }, } /scriptcreateForm()来自 formily/core返回的 Form 实例是表单唯一的 ViewModelFormProvider负责将其下发给所有子组件。JSON Schema 开发模式该模式将 JSON Schema 直接传给SchemaField的schema属性Schema 可以是离线存储、动态下发的数据适合可配置化 / 低代码场景template FormProvider :formform SchemaField :schemaschema / /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组件注册表会与SchemaField的componentsprop 合并options.components与props.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 :formform SchemaField SchemaStringField x-componentInput :x-component-props{ placeholder: 请输入 } / div我不会被渲染/div SchemaVoidField x-content我会被渲染 / SchemaVoidField :x-contentComp / /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会额外生成SchemaStringField、SchemaObjectField、SchemaArrayField、SchemaBooleanField、SchemaDateField、SchemaDateTimeField、SchemaVoidField、SchemaNumberField等标记组件见 SchemaField.ts 的SchemaFieldFactory它们统一包装内部的MarkupField把标签上的属性解析为 Schema 节点添加到父级 Schema 的propertiesobject/void 类型或itemsarray 类型中最终整个 Markup 结构被转换为一份 JSON Schema 交给 RecursionField 渲染。x-*系列属性如x-component、x-decorator、x-validator、x-reactions、x-visible、x-disabled、x-read-pretty等以及标准 JSON-Schema 关键字enum、pattern、maximum、required等都作为标记组件的 props 被解析。安装与快速开始formily/vue通过vue-demi同时兼容 Vue 2 与 Vue 3peerDependencies 声明vue: ^2.6.0 || 3.0.0-rc.0见 packages/vue/package.json官方安装命令如下Vue 3$ npm install --save formily/core formily/vueVue 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 目录对应field、schema-field、array-field、object-field、void-field、form-provider、form-consumer、recursion-field、connect、map-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点击查看免费下载相关推荐Formily 的 MVVM 架构定位从 OOP 到 FP理解表单响应式模型的底层设计Formily 的 MVVM 架构定位从 OOP 到 FP理解表单响应式模型的底层设计 导读 本文基于 Formily 官方内核文档 mvvm.zh CN.前端UI组件Mantle设计模式面向协议的模型层架构Mantle设计模式面向协议的模型层架构 你是否还在为iOS开发中的JSON解析和模型转换编写大量重复代码是否在面对复杂数据模型时感到维护困难Mantle移动开发Formily React 指南formily/react 的架构、模型绑定与三种开发模式Formily React 指南formily/react 的架构、模型绑定与三种开发模式 导读 formily/react 是 Formily 表单方案前端UI组件上一篇Mac版Navicat无限试用终极指南三种简单方法免费使用Navicat Premium下一篇3DSident如何彻底改变3DS系统检测体验深度解析CIA架构的技术革命创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表