ARTICLE DETAIL

资讯详情

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

Formily Vue SchemaField 组件详解:Markup Schema 协议驱动表单的完整指南

Formily Vue SchemaField 组件详解: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/vue中用于解析 JSON-Schema 动态渲染表单的核心组件SchemaField系统讲解其 Markup SchemaJSX/模板声明式 Schema与 JSON Schema纯对象 Schema两种使用形态。通过本文你将掌握createSchemaField工厂函数的签名与作用域注入机制、SchemaField 全家桶组件的职责划分、表达式协议的编译原理以及如何在 Vue 2 / Vue 3 项目中以写组件的方式声明出可递归渲染、可联动、可扩展的动态表单。SchemaField 是什么SchemaField是formily/vue中专门用于解析 JSON-Schema 动态渲染表单的组件。它的核心价值在于把表单是什么从表单怎么渲染中彻底分离——开发者只需要描述 Schema字段类型、布局、组件、联动规则渲染由 SchemaField 自动递归完成。SchemaField 的组件标识约定x-component与x-decorator的取值与createSchemaField传入的组件集合components中的 Key 一一匹配详见 ISchema 属性说明。使用 SchemaField 之前必须先通过createSchemaField工厂函数创建 SchemaField 组件实例。这样设计的目的有两个组件映射隔离每个业务模块可以按需注入自己的字段组件集合Schema 中的字符串标识只在该集合内解析避免全局组件命名污染作用域注入工厂函数与组件实例都可以注入 scope作为协议表达式{{expression}}的变量来源。createSchemaField 签名解析工厂函数返回的组件集合createSchemaField返回一个ComposeSchemaField对象包含 SchemaField 主组件和一系列Markup 字段组件type ComposeSchemaField { SchemaField: Vue.Componentany, any, any, ISchemaFieldProps SchemaMarkupField: Vue.Componentany, any, any, ISchema SchemaStringField: Vue.Componentany, any, any, OmitISchema, type SchemaObjectField: Vue.Componentany, any, any, OmitISchema, type SchemaArrayField: Vue.Componentany, any, any, OmitISchema, type SchemaBooleanField: Vue.Componentany, any, any, OmitISchema, type SchemaDateField: Vue.Componentany, any, any, OmitISchema, type SchemaDateTimeField: Vue.Componentany, any, any, OmitISchema, type SchemaVoidField: Vue.Componentany, any, any, OmitISchema, type SchemaNumberField: Vue.Componentany, any, any, OmitISchema, type }SchemaField协议驱动渲染的主入口负责收集子级 Markup 字段、装配 Schema 并交给递归渲染SchemaStringField / SchemaObjectField / SchemaArrayField / SchemaBooleanField / SchemaDateField / SchemaDateTimeField / SchemaVoidField / SchemaNumberField分别对应string / object / array / boolean / date / datetime / void / number类型的声明式字段组件它们的 props 都是OmitISchema, type——即 type 由组件名决定其余属性全部透传给 SchemaSchemaMarkupField不限定 type 的通用 Markup 字段通过typeprop 显式指定类型。从源码实现看SchemaField.tsSchemaStringField等组件是由SchemaFieldFactory(type, name)工厂批量生成的它们只是把自身type固定后透传给MarkupField。因此使用效果上SchemaStringField /等价于SchemaMarkupField typestring /。工厂函数参数interface ISchemaFieldFactoryProps { components?: { [key: string]: Vue.Component //组件列表 } scope?: any //全局作用域用于实现协议表达式变量注入 }components字段组件注册表key 是字符串标识供x-component/x-decorator引用value 是 Vue 组件scope全局表达式作用域注入后所有 Schema 表达式均可访问例如在表达式中引用业务常量或外部函数见下文表达式作用域。SchemaField 组件属性interface ISchemaFieldProps extends IFieldFactoryProps { schema?: ISchema //字段schema scope?: any //协议表达式作用域 name?: string //字段名称 }schema直接传入 JSON Schema 对象用于纯对象式的 JSON Schema 渲染不写 Markup 子组件scope组件级作用域与工厂函数scope通过lazyMerge合并优先级高于工厂级 scopename字段名称决定字段在表单数据树中的路径。IFieldFactoryProps与ISchema的完整定义可分别参考 IFieldFactoryProps 与 ISchema。工厂内建的其他属性除了文档签名中的属性从 SchemaField.ts 可以看到 SchemaField 组件还接收以下 props它们随后被透传给内部递归渲染属性类型说明basePathFormPathPattern字段基础路径用于指定 schema 挂载的数据路径前缀onlyRenderPropertiesboolean是否只渲染 properties 子字段onlyRenderSelfboolean是否只渲染自身、不渲染子字段mapProperties(schema, name) Schemaproperties 映射器可改写子 schema 后渲染filterProperties(schema, name) booleanproperties 过滤器返回 false 的节点不渲染这些属性与独立使用的RecursionField见 RecursionField 文档完全对齐——事实上 SchemaField 内部正是把装配好的 schema 交给RecursionField完成递归渲染的。SchemaField 与 RecursionField 的关系文档明确指出RecursionField是 SchemaField 内部的核心渲染组件RecursionField 文档。从 SchemaField.ts 的渲染逻辑可以看到SchemaField 把默认插槽Markup 字段树放入渲染队列同时基于schemaRef渲染一个RecursionField将装配完成的 Schema 传入RecursionField负责把 Schema 节点转换为真实的 Field 模型并驱动组件渲染。因此RecursionField也可以脱离 SchemaField 独立使用——常见场景是在自定义容器组件内部读取useFieldSchema()拿到的子 schema再手动递归渲染。例如 schema.markup.spec.ts 中CustomObject组件的做法template div>template FormProvider :formform SchemaField SchemaStringField nameinput x-componentInput / /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 { SchemaField, SchemaStringField } createSchemaField({ components: { Input, }, }) export default { components: { FormProvider, SchemaField, SchemaStringField }, data() { return { form: createForm(), } }, } /script关键点FormProvider负责提供formily/core的 form 实例上下文SchemaStringField nameinput x-componentInput /声明了一个名为input、渲染组件为Input的字符串字段x-component的值必须能在createSchemaField({ components })的注册表中找到。Markup 字段的完整 props从 SchemaField.ts 的markupProps定义可以看出所有 Markup 字段组件几乎完整透传了 ISchema 的全部属性包括基础描述name、title、description、default、readOnly、writeOnly数据校验enum、const、multipleOf、maximum、exclusiveMaximum、minimum、exclusiveMinimum、maxLength、minLength、pattern、maxItems、minItems、uniqueItems、maxProperties、minProperties、required、format结构描述properties、items、additionalItems、patternProperties、additionalPropertiesUI 协议xIndex、xPattern、xDisplay、xValidator、xDecorator、xDecoratorProps、xComponent、xComponentProps、xReactions、xContent状态协议xVisible、xHidden、xDisabled、xEditable、xReadOnly、xReadPretty。以 Vue 组件 props 的形式使用时需注意Markup 字段把x-component这类带连字符的键直接作为 prop 名模板中写作x-componentInput等价于 JSON Schema 中的x-component: Input。嵌套与数组场景数组、对象、布局容器都可以用组件树自然表达。参考 schema.markup.spec.ts 中的数组用例FormProvider :formform SchemaField SchemaArrayField SchemaObjectField SchemaStringField x-componentInput / /SchemaObjectField SchemaVoidField / /SchemaArrayField /SchemaField /FormProviderSchemaArrayField声明数组类型嵌套的SchemaObjectField会成为数组元素结构itemsSchemaVoidField是不占数据空间的字段常用于布局容器卡片、分组、Grid 等它不会在表单值中产生数据节点。未命名字段的自动编号从源码看Markup 字段如果未提供nameSchemaField 会自动生成NO_NAME_FIELD_$N形式的占位名称SchemaField.ts并在每次 SchemaField 渲染前重置计数器env.nonameId 0。这保证了匿名声明式字段也能稳定渲染同时避免跨渲染泄漏递增编号。Markup 字段的装配原理Markup 字段本身并不直接渲染 UI而是在 setup 阶段通过inject(SchemaMarkupSymbol)获取父级 Schema 节点然后调用parentRef.addProperty(name, schema)或parentRef.setItems(...)把自己挂载到父节点上SchemaField.ts。最终渲染时输出一个display: none的空 div 占位真正的 UI 由 SchemaField 内部的 RecursionField 统一驱动。这也是为什么 Markup 字段必须位于SchemaField内部——脱离父级 Schema 上下文时源码中 no parent 分支它只会渲染空模板。JSON Schema 用法直接传入 Schema 对象如果不希望用模板组件树SchemaField 也支持直接传入 JSON Schema 对象schema-field-with-schema.vuetemplate FormProvider :formform SchemaField :schema{ type: object, properties: { input: { type: string, x-component: Input, }, }, } /SchemaField /FormProvider /template script import { Input } from ant-design-vue import { createForm } from formily/core import { FormProvider, createSchemaField } from formily/vue const { SchemaField } createSchemaField({ components: { Input, }, }) export default { components: { FormProvider, SchemaField }, data() { return { form: createForm(), } }, } /script这种形态特别适合后端驱动的场景接口下发 Schema JSON前端原样渲染天然支持表单动态化与可视化搭建。从 SchemaField.ts 的实现看schema prop 会经过一层归一化如果传入的已经是Schema实例Schema.isSchemaInstance判断直接复用否则会用new Schema({ type: object, ...props.schema })包装成 Schema 实例。也就是说SchemaField 始终工作在SchemaClass 之上纯 JSON 只是它的序列化形态。测试用例schema.json.spec.ts验证了字符串与对象两种 Schema 的直接渲染包括default: 123会正确成为字段初始值。Schema Class协议驱动的底层引擎SchemaField的底层依赖是formily/vue导出的SchemaClassschema.md它是协议驱动最核心的部分拥有三大能力解析 json-schema基于一份 JSON 数据创建一棵 Schema Tree每个节点都是带方法的 Schema 实例将 json-schema 转换成 Field Model通过toFieldProps()把 Schema 属性映射为formily/core的IFieldFactoryProps映射关系见 属性表编译 json-schema 表达式深度递归编译{{expression}}片段消费作用域变量。Schema可以从formily/vue导出也可以单独依赖formily/json-schema包使用其源码位于 packages/json-schema。Schema 的关键属性与字段模型映射Schema 属性分为三类理解它们对用好 SchemaField 至关重要标准 JSON-Schema 校验属性type、enum、const、maximum、minimum、pattern、maxLength、minLength、required、format等会被映射为字段的validator或dataSource用于声明式校验UI 协议属性x-component、x-decorator、x-component-props、x-decorator-props、x-pattern、x-display、x-visible、x-hidden、x-disabled、x-editable、x-read-only、x-read-pretty等决定字段用什么组件渲染、以什么交互模式呈现映射到字段模型的component、decorator、pattern、display、visible、disabled、readOnly等状态扩展协议属性x-reactions、x-content、x-index、x-data、definitions、$ref提供联动、插槽内容、排序、自定义数据等高级能力。其中$ref仅支持#/definitions/xxx格式的本地引用从 Schema 预定义中读取并合并不支持加载远程 JSON Schema这一点在引入远程 Schema 方案时需要特别注意。Schema 的常用方法Schema Class 提供了一套操作 Schema Tree 的方法schema.md方法说明addProperty(key, schema)添加属性描述返回新 SchemaremoveProperty(key)移除属性描述setProperties(properties)覆盖式更新属性描述addPatternProperty(regexp, schema)添加正则属性描述patternPropertiessetItems(items)覆盖式更新数组项描述mapProperties(mapper)按x-index顺序遍历映射 propertiesreduceProperties(reducer, initialValue)按x-index顺序归约 propertiescompile(scope)深度递归编译表达式片段返回 SchemafromJSON(json)/toJSON()Schema 与普通 JSON 互转toFieldProps()转换为 Formily 字段模型属性静态方法中比较常用的是isSchemaInstance判断对象是否为 Schema 实例、registerCompiler注册自定义表达式编译器、registerTypeDefaultComponents给 Schema 类型注册默认组件与enablePolyfills([1.0])开启 1.x 协议兼容垫片自动转换x-linkages→x-reactions、x-props→x-decorator-props、x-rules→x-validator等。表达式协议与作用域注入表达式语法Schema 的每个属性都能使用字符串表达式{{expression}}表达式变量可从createSchemaField或SchemaField组件中传入schema.md。表达式片段约定以{{开头、}}结尾的字符串代表一个表达式片段编译时深度递归整个 Schema 对象。表达式的作用域合并遵循组件级覆盖工厂级的规则scopeRef lazyMerge(options.scope, props.scope)SchemaField.ts并通过provide(SchemaExpressionScopeSymbol, scopeRef)向下传递。测试用例 expression.scope.spec.ts 验证了嵌套作用域的行为SchemaField的 scope 中注入$outerScope内部ExpressionScope组件再注入$innerScope表达式{{$innerScope $outerScope}}可以同时访问两层变量——作用域是可以叠加的。内置表达式作用域为了支撑联动SchemaField 内置了一组作用域变量schema.md变量说明可用位置$self当前字段实例普通属性表达式、x-reactions$values顶层表单数据普通属性表达式、x-reactions$form当前 Form 实例普通属性表达式、x-reactions$observable创建响应式对象与 observable 用法一致表达式$memo创建持久引用数据与 autorun.memo 一致表达式$effect响应 autorun 首次执行的微任务时机与 dispose表达式$dependencies/$deps读取 x-reactions 中 dependencies 声明的依赖值数组顺序一致仅 x-reactions 表达式$target主动联动模式的 target 字段仅 x-reactions 表达式例如在 SchemaField 上注入 scope 后联动表达式可以直接消费外部变量SchemaField :schemaschema :scope{ test: 123 } /对应测试见 schema.json.spec.tsx-reactions的fulfill.state.value: {{ test }}成功把test变量的值写入了目标字段。x-reactions 联动协议x-reactions是 SchemaField 场景下最常用的联动协议SchemaReactions分为两种模式主动联动reaction 对象包含target目标字段路径支持 FormPathPattern 语法不支持相对路径并配合when条件、fulfill满足时、otherwise不满足时描述联动行为被动联动reaction 对象通过dependencies声明依赖字段路径支持相对路径、source#property取详细属性、对象别名等形式用$deps在表达式中消费依赖值。fulfill/otherwise内部既可以更新字段状态state也可以更新 Schema 协议schema还可以执行脚本语句run形如$form.setFieldState(...)且支持通过effects声明独立的生命周期钩子如onFieldInputValueChange。三种形态的完整写法示例见 schema.md 的联动用例。schema.markup.spec.ts中有一个完整的联动集成测试字段aaa输入123后bbb字段依赖aaa的 when 条件显示bbb输入123后通过target: ccc主动联动让ccc显示。这印证了 Markup Schema 下声明式联动的完整链路。x-content 插槽内容协议x-content用于向x-component组件传入子节点插槽内容。从 schema.json.spec.ts 的测试矩阵可以看到它支持非常灵活的形式字符串/组件x-content: 123或直接传组件对象作为默认插槽内容具名插槽对象{ content: Content }、{ default: Content }等按插槽名分发作用域插槽x-content传函数式组件时可以消费父组件通过scopedSlots传入的 slotProp表达式注入x-content: {{Content}}配合 scope 从外部注入组件测试用例named slot with scope验证了这一点x-slot 协议在 void/object 字段的properties中声明x-slot: content的子字段可把该子字段渲染为父组件的具名插槽见 x-slot 测试。这一机制让布局容器 插槽内容完全协议化是 Formily 实现复杂自定义布局如卡片标题栏、表格操作列的关键支撑。常见使用注意事项必须配合 FormProviderSchemaField 渲染依赖 form 上下文使用时需用FormProvider :formform包裹官方 demo 与全部测试用例均如此组件必须注册x-component/x-decorator指向的标识必须存在于createSchemaField的components中否则无法解析Markup 字段不能脱离 SchemaFieldMarkup 字段依赖父级 Schema 上下文完成挂载脱离后仅渲染空占位表达式以{{开头}}结尾只有这种形式的字符串才会被编译普通字符串原样透传$ref不支持远程加载仅支持#/definitions/xxx本地引用Vue 2 / Vue 3 兼容formily/vue基于 vue-demi 实现同一套 API 可在两个版本下运行测试文件同时使用vue/test-utils与vue/composition-api验证 Vue 2 兼容性。小结SchemaField 是 Formily Vue 协议驱动表单的核心入口通过createSchemaField工厂注入组件与作用域既可以用 Markup 组件树以写组件的方式声明表单也可以直接传入 JSON Schema 对象实现纯数据驱动渲染。其底层由SchemaClass 提供解析、字段模型转换与表达式编译能力由RecursionField完成递归渲染再配合x-reactions联动协议、x-content插槽协议与内置表达式作用域即可覆盖从简单表单到复杂动态表单、从本地声明到后端驱动的全部场景。赞分享前端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 SchemaField 组件详解JSON Schema 动态表单渲染的完整实战指南Formily SchemaField 组件详解JSON Schema 动态表单渲染的完整实战指南 导读 SchemaField 是 Formily Reac前端UI组件Formily 动态表单核心组件 SchemaField 完全指南Markup Schema 与 JSON Schema 双模式实战Formily 动态表单核心组件 SchemaField 完全指南Markup Schema 与 JSON Schema 双模式实战 SchemaField前端UI组件Formily 自增列表实战ArrayItems 组件详解Markup Schema / JSON Schema / 联动全场景Formily 自增列表实战ArrayItems 组件详解Markup Schema / JSON Schema / 联动全场景 ArrayItems 是前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表