ARTICLE DETAIL

资讯详情

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

Formily Vue useFieldSchema 完全指南:在自定义组件中读取当前字段的 Schema 信息

Formily Vue useFieldSchema 完全指南:在自定义组件中读取当前字段的 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点击查看免费下载导读useFieldSchema是 Formily Vueformily/vue提供的一个内置 Composition API Hook用于在自定义组件内部读取当前字段所对应的 Schema 描述。在协议驱动的表单架构中组件与数据模型Field Model解耦组件侧往往需要拿到描述自身是什么、长什么样的 JSON Schema 元信息才能做出正确的渲染与交互决策。读完本文你将掌握useFieldSchema的签名、注入原理、使用边界并能结合Schema类的方法toJSON、toFieldProps、compile等在SchemaField/RecursionField子树中实现基于 Schema 的自定义渲染组件。1. 什么是 useFieldSchema协议驱动场景下的元信息读取口在 Formily 的 Vue 实现中表单渲染分为两条技术路线普通模式Model 驱动直接使用Field、ObjectField、ArrayField、VoidField组件与formily/core的字段模型交互协议模式JSON Schema 驱动通过SchemaField解析 JSON Schema 动态渲染表单字段的 UI 形态完全由 Schema 描述。useFieldSchema正是为协议模式服务的。它的官方定位是主要在自定义组件中读取当前字段的 Schema 信息并且只能用在SchemaField或者RecursionField的子树中使用见 use-field-schema.md。通俗地说当你在createSchemaField中注册了一个自定义组件并且这个组件被某个x-component: YourCustom的 Schema 节点引用时该组件内部就可以通过useFieldSchema()拿到这个 Schema 节点本身——也就是描述我自己的那份协议数据。interface useFieldSchema { (): RefSchema }2. 源码实现一次极简的 provide / injectuseFieldSchema的实现非常简洁完整源码位于 useFieldSchema.tsimport { inject, ref } from vue-demi import { SchemaSymbol } from ../shared/context export const useFieldSchema () { return inject(SchemaSymbol, ref()) }它做且只做一件事从当前组件上下文通过inject取出SchemaSymbol对应的响应式引用默认值是一个空的ref()。由于返回值是RefSchema在 Vue 模板或setup中需要通过.value访问实际的Schema实例。SchemaSymbol的定义位于 context.ts它是一组 Vue 注入键InjectionKey之一export const SchemaMarkupSymbol: InjectionKeyRefSchema Symbol(schemaMarkup) export const SchemaSymbol: InjectionKeyRefSchema Symbol(schema)注意这里有两个容易混淆的注入键SchemaMarkupSymbolSchemaField组件在解析标记式MarkupSchema时注入的父级 Schema 引用见 SchemaField.ts供SchemaObjectField等标记字段把自身挂载到父 Schema 上SchemaSymbolRecursionField渲染当前节点时注入的当前字段 Schema正是useFieldSchema读取的目标。注入链谁 provide谁 injectSchemaSymbol的provide发生在 RecursionField.tsconst fieldSchemaRef computed(() createSchema(props.schema)) // ... provide(SchemaSymbol, fieldSchemaRef)也就是说每当RecursionField基于一份 schema 递归渲染时它就会把new Schema(schema)得到的实例以Ref形式注入到子树中。而SchemaField内部最终也是通过渲染RecursionField来下发 Schema 的见 SchemaField.ts。因此在SchemaField或RecursionField的子树里调用useFieldSchema()拿到的一定是最近一层 RecursionField 正在渲染的那个 Schema 节点。这条调用链也解释了官方文档中只能用在SchemaField或RecursionField子树中的约束脱离这两个组件上下文里没有SchemaSymbolinject就会退回默认的空ref()此时schemaRef.value为undefined无法取得有效 Schema。3. 使用边界与常见误区基于源码机制可以总结出以下必须注意的使用边界只能在协议驱动的组件树中使用组件必须由SchemaField或其内部的RecursionField渲染才能保证SchemaSymbol被注入不要在普通 Model 驱动组件中使用例如直接放在FormProvider下、与 Schema 无关的纯 UI 组件取到的将是空引用拿不到就做兜底因为默认值是ref()对schemaRef.value的使用前应做空值判断如v-ifschema或if (!schema) return ...返回的是 Schema 实例而非普通 JSONSchema是formily/json-schema提供的类自带解析、编译、转换等方法详见下文第 5 节需要序列化时显式调用toJSON()。4. 完整用例在自定义组件中打印当前字段 Schema原文档通过一个dumi-previewer演示组件挂载了官方 demo其源码位于 use-field-schema.vue。下面给出完整、可运行的版本并逐段讲解template FormProvider :formform SchemaField SchemaObjectField namecustom x-componentCustom :x-component-props{ schema: { type: object, properties: { input: { type: string, x-component: Custom, }, }, }, } / /SchemaField /FormProvider /template script import { defineComponent, h } from vue/composition-api import { createForm } from formily/core import { FormProvider, createSchemaField, useFieldSchema } from formily/vue import ant-design-vue/dist/antd.css const Custom defineComponent({ setup() { const schemaRef useFieldSchema() return () { const schema schemaRef.value return h( div, { style: { whiteSpace: pre }, }, [JSON.stringify(schema.toJSON(), null, 4)] ) } }, }) const { SchemaField, SchemaObjectField } createSchemaField({ components: { Custom, }, }) export default { components: { FormProvider, SchemaField, SchemaObjectField }, data() { const form createForm({ validateFirst: true }) return { form, } }, } /script关键点拆解createSchemaField工厂createSchemaField接受{ components, scope }两个可选参数签名见 schema-field.mdcomponents中的Custom就是被x-componentCustom引用的组件SchemaObjectField标记字段通过namecustom与x-componentCustom声明一个对象类型的标记节点其x-component-props里携带了一份嵌套的 JSON Schema——这份 Schema 会被RecursionField递归解析组件内部消费Custom的setup中调用useFieldSchema()拿到schemaRef渲染函数里用schema.toJSON()把Schema实例序列化为纯 JSON 并格式化打印。由于schema中嵌套的input字段同样指定了x-component: Custom递归渲染时内层Custom拿到的又是它自己的 Schema 节点——这正是每个节点读取自己那份协议的直观体现。运行后页面会把当前字段的完整 Schema包含type、properties、x-component等以格式化 JSON 的形式渲染出来。5. 拿到 Schema 之后Schema 实例的核心能力useFieldSchema()返回的RefSchema中Schema是formily/json-schema提供的通用类SchemaField与RecursionField都依赖它。其能力在 schema.md 中有完整文档这里重点列出与自定义组件读取 Schema最相关的部分5.1 序列化与反序列化toJSON(): ISchema——把当前Schema对象还原成普通 JSON 数据是读取并展示/传递 Schema最常用的方法上文 demo 即用此方法fromJSON(json: ISchema): Schema——把普通 JSON 转成Schema对象isSchemaInstance(target)——判断一个对象是否为Schema实例。5.2 转换成字段模型属性toFieldProps(): IFieldFactoryProps——把当前Schema对象转换成 Formily 字段模型属性IFieldFactoryProps。RecursionField内部正是通过schema?.toFieldProps?.({ ...optionsRef.value, scope })来生成字段 props 的见 RecursionField.ts。自定义组件如果要做协议 → 模型的桥接可以复用这一方法。5.3 表达式编译compile(scope): Schema——深度递归当前 Schema 中的{{expression}}表达式片段并编译支持传入作用域对象静态方法Schema.compile(target, scope)/Schema.shallowCompile(target, scope)——编译任意对象中的表达式片段Schema.registerCompiler(compiler)——注册自定义表达式编译器Schema.silent(value?)——控制表达式编译出错时是否静默。createSchemaField与SchemaField组件都支持传入scope全局 / 局部表达式作用域两者会被lazyMerge合并后注入见 SchemaField.ts供{{$form}}、{{$self}}、{{$values}}等内置作用域变量消费。5.4 属性树操作addProperty(key, schema)/removeProperty(key)/setProperties(properties)——增删改子属性描述addPatternProperty(regexp, schema)/setItems(items)等——操作正则属性与数组项描述mapProperties(mapper)/reduceProperties(reducer, initialValue?)——按x-index顺序遍历properties。5.5 常见属性速查Schema同时承载了 JSON Schema 标准属性与 Formily 扩展属性x-*系列自定义组件中常用的包括属性含义type字段类型string/object/array/number/boolean/void/date/datetime等title/description标题与描述default默认值映射为字段initialValueenum枚举映射为dataSourcerequired/pattern/format等校验规则映射为validatorx-component/x-component-props字段 UI 组件及其属性x-decorator/x-decorator-props字段 UI 包装器组件及其属性x-visible/x-hidden/x-disabled/x-editable/x-read-pretty显隐、禁用、只读等交互状态x-reactions字段联动协议x-data扩展自定义数据完整的属性表、字段模型映射关系与方法签名可查阅 schema.md。6. 与兄弟 Hooks 的分工useField / useForm / useParentFormformily/vue在 hooks/index.ts 中统一导出了一组 hooksuseFieldSchema与它们互补构成自定义组件的上下文三件套Hook读取内容典型用途useFieldSchema()当前字段的Schema 实例RefSchema读取协议元信息、按协议动态渲染useField()当前字段的Field ModelRefGeneralField读取/操作字段值、状态、校验实现见 useField.ts读取FieldSymboluseForm()最近的Form 实例表单级操作提交、校验、查询字段useParentForm()向上查找的Form 实例在弹窗/抽屉等隔离场景中穿透查找表单useFormEffects()表单生命周期副作用订阅字段挂载、值变化等事件一个实用的组合模式是用useFieldSchema()决定怎么渲染用useField()决定渲染什么数据两者结合即可写出完全由协议驱动、可高度复用的自定义组件。例如setup() { const schemaRef useFieldSchema() // 当前字段协议 const fieldRef useField() // 当前字段模型 return () { const schema schemaRef.value const field fieldRef.value if (!schema) return null // 依据 schema[x-component-props] 与 field.value 定制渲染 } }7. 常见问题排查Q1在自定义组件里调用useFieldSchema()后schemaRef.value是undefined检查组件是否真的位于SchemaField/RecursionField的子树中以及该组件是否通过x-component被 Schema 节点引用。脱离协议树渲染时inject会命中默认值ref()空引用这是源码设计使然见 useFieldSchema.ts。Q2useFieldSchema()拿到的对象为什么不能直接JSON.stringify因为拿到的是Schema类实例含原型方法直接序列化得不到干净的协议数据。应调用schema.toJSON()见第 5.1 节。Q3想按 Schema 类型做分支渲染怎么做读取schema.value.type或schema.value[x-component]即可。注意 Markup Schema 场景下x-component必须与createSchemaField({ components })注册的 key 完全匹配否则组件无法被解析见 schema.md。结语useFieldSchema是 Formily Vue 协议驱动体系的元信息读取口它通过provide/inject机制把RecursionField当前渲染节点的Schema实例以RefSchema的形式下发给子树让自定义组件能够认识自己。理解它的注入链SchemaField→RecursionField→provide(SchemaSymbol)→useFieldSchemainject、使用边界以及与useField/useForm等 hooks 的分工你就能写出真正协议驱动、按 Schema 自我描述渲染的高复用表单组件。相关实现与文档可继续阅读Hook 实现useFieldSchema.ts注入上下文定义context.ts注入方实现RecursionField.ts、SchemaField.ts完整 demouse-field-schema.vueSchema 类全量文档schema.md赞分享前端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 React 中 useFieldSchema Hook 完全指南在自定义组件中读取当前字段 SchemaFormily React 中 useFieldSchema Hook 完全指南在自定义组件中读取当前字段 Schema 导读 useFieldSchema前端UI组件formily 自定义组件读取字段 Schema 指南useFieldSchema 的原理与实战用法formily 自定义组件读取字段 Schema 指南useFieldSchema 的原理与实战用法 在 formily 的 formily/react 体前端UI组件Formily React useField Hook 完全指南在自定义组件中读取字段模型与状态Formily React useField Hook 完全指南在自定义组件中读取字段模型与状态 导读 useField 是 Formily React 体系前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表