首页/新闻资讯/正文详情

Formily Vue 的 injections 上下文注入体系:FormContext 与 Schema 系列注入详解

发布时间:2026/9/25 8:53:10 来源:云帆数科 栏目:资讯中心
Formily Vue 的 injections 上下文注入体系:FormContext 与 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 的 injections 是一套基于 Vue 3 Composition API经 vue-demi 同时兼容 Vue 2的依赖注入上下文集合。它把表单实例、字段实例与 JSON Schema 运行时信息封装成 6 个可消费的注入项是useForm、useField、useFieldSchema等核心 Hook 以及SchemaField递归渲染链路得以工作的底层基石。阅读本文后你将能理解每个注入项的类型签名、provide 来源与消费方式并能在自定义组件与高阶封装中正确使用这些上下文。总览六个注入项与底层 Symbol所有注入项都定义在 packages/vue/src/shared/context.ts每个注入项由一个InjectionKeySymbol与对应的injectT(Symbol)消费表达式组成全部在FormProvider或SchemaField内部通过provide注入注入项类型由谁 provideFormContextRefFormFormProviderFieldContextRefGeneralFieldReactiveFieldSchemaMarkupContextRefSchemaSchemaField/MarkupFieldSchemaContextRefSchemaRecursionFieldSchemaExpressionScopeContextRefRecordstring, anySchemaField/ExpressionScopeSchemaOptionsContextRefISchemaFieldVueFactoryOptionsSchemaField需要注意这些注入值的实际类型都是 Vue 的Ref响应式引用而不是裸实例——因为 Formily 的字段、Schema 都是响应式对象以 Ref 形式提供才能保证消费方随状态变化重新渲染。这一点在 context.ts 中由InjectionKeyRef...的泛型签名明确体现。FormContext获取当前 Form 实例描述Form 上下文可以获取当前 Form 实例。签名import { Form } from formily/core const FormContext injectForm(FormSymbol)FormSymbol的类型为InjectionKeyRefForm。它在 FormProvider.ts 中被提供FormProvider通过useAttach(toRef(props, form))将传入的 form 包装为 Ref 后执行provide(FormSymbol, formRef)。同时FormProvider的 setup 中还会调用useInjectionCleaner清理其余 5 个注入项FieldSymbol、SchemaMarkupSymbol、SchemaSymbol、SchemaExpressionScopeSymbol、SchemaOptionsSymbol确保每个FormProvider边界内的字段级上下文不会串到外层从源码看这是 FormProvider.ts 的固定行为。官方封装好的消费方式是 useForm.tsimport { inject, Ref, ref } from vue-demi import { Form } from formily/core import { FormSymbol } from ../shared/context export const useForm (): RefForm { const form inject(FormSymbol, ref()) return form }inject的第二个参数是默认值在FormProvider之外使用时useForm会返回一个空 Ref不会抛错。因此自定义组件中应优先使用useForm()而非直接inject(FormSymbol)。FieldContext获取当前字段实例描述字段上下文可以获取当前字段实例。签名import { GeneralField } from formily/core const FieldContext injectGeneralField(FieldSymbol)FieldSymbol类型为InjectionKeyRefGeneralFieldGeneralField是Field、ArrayField、ObjectField、VoidField的联合抽象保证在任意字段组件中都能拿到统一的字段接口。它的提供方是 ReactiveField.tsReactiveField的 setup 中会依据formRef与父字段parentRef调用form.createXXXField(...)创建字段实例随后执行provide(FieldSymbol, fieldRef)将字段以 Ref 形式注入子树。ReactiveField本身又被observer包裹因此字段状态变化会驱动依赖该注入项的组件更新。消费侧同样有封装好的 useField.tsimport { inject, Ref, ref } from vue-demi import { GeneralField } from formily/core import { FieldSymbol } from ../shared/context export const useField T GeneralField(): RefT { return inject(FieldSymbol, ref()) as any }通过useField()自定义组件可以获得当前字段实例进而读取field.value、field.display、field.pattern等响应式状态这是编写自定义 Formily 字段组件Custom Component的基础能力。在ReactiveField渲染阶段display ! visible的字段会直接渲染为空的template见 ReactiveField.ts所以依赖FieldContext的组件只会作用于可见字段。SchemaMarkupContext收集 JSX Markup 写法的 Schema 标签描述Schema 标签上下文主要用于收集 JSX Markup 写法的 Schema 标签然后转换成标准 JSON Schema。签名SchemaMarkupContext injectSchema(SchemaMarkupSymbol)这是 Formily「Schema 标签化Markup」能力的关键注入项。SchemaField在 setup 中先provide(SchemaMarkupSymbol, schemaRef)见 SchemaField.ts把当前SchemaField的根 Schema 作为收集容器随后渲染子树中的SchemaMarkupField/SchemaStringField/SchemaObjectField等标签组件。MarkupField的 setup 会通过inject(SchemaMarkupSymbol, null)取到父级 Schema 容器再根据父级类型调用parentRef.value.addProperty(name, schema)object/void 类型或setItems(...)array 类型把标签 props 转换出的标准 JSON Schema 挂载到父 Schema 上见 SchemaField.ts。挂载后MarkupField还会provide(SchemaMarkupSymbol, schemaRef)继续向下传递形成嵌套收集最终这些被收集的properties会交给紧随其后的RecursionField递归渲染SchemaField.ts。MarkupField渲染结果是一个display: none的 divSchemaField.ts即标签本身不可见只承担 Schema 收集职责。因此该上下文主要面向 Schema 内部渲染机制用户一般无需直接消费但如果要自定义 Schema 收集行为它就是唯一的注入入口。SchemaContext获取当前字段的 Schema 信息描述字段 Schema 上下文主要用于获取当前字段的 Schema 信息。签名const SchemaContext injectSchema(SchemaSymbol)SchemaSymbol类型为InjectionKeyRefSchemaSchema来自formily/json-schema。提供方是 RecursionField.tsRecursionField会把props.schema通过new Schema(schemaProp)实例化markRaw包装避免不必要的响应式代理并执行provide(SchemaSymbol, fieldSchemaRef)保证其子树内每个组件都能读到当前层级的 Schema。官方消费封装为 useFieldSchema.tsimport { inject, ref } from vue-demi import { SchemaSymbol } from ../shared/context export const useFieldSchema () { return inject(SchemaSymbol, ref()) }结合useField与useFieldSchema自定义组件可以同时拿到「字段实例」与「Schema 描述」例如读取schema[x-component-props]中的配置来定制渲染行为。RecursionField的getPropsFromSchema调用schema.toFieldProps(...)时还会合并SchemaOptionsContext与SchemaExpressionScopeContext作为表达式作用域见 RecursionField.ts这也是x-reactions等表达式能解析到外部变量的底层原因之一。SchemaExpressionScopeContextSchema 表达式作用域描述Schema 表达式作用域上下文。签名const SchemaExpressionScopeContext injectany(SchemaExpressionScopeSymbol)SchemaExpressionScopeSymbol实际类型为InjectionKeyRefRecordstring, any见 context.ts。它承载 Schema 内x-*表达式如x-visible、x-reactions、x-component-props中的函数/表达式可以访问的外部变量集合。提供方有两处SchemaField在 setup 中通过computed(() lazyMerge(options.scope, props.scope))合并工厂参数 scope 与组件 props 传入的 scope 后provideSchemaField.tsExpressionScope.ts 组件会读取当前作用域并与自己的valueprop 做lazyMerge再向下provide实现局部作用域的叠加与覆盖。RecursionField中toFieldProps的scopegetter 也是将optionsRef.value.scope与scopeRef.value合并RecursionField.ts与SchemaField的合并逻辑一致。需要强调的是lazyMerge是浅层合并因此ExpressionScope覆盖同名 key 时是整值替换而非深度合并。SchemaOptionsContextcreateSchemaField 传入的全局参数描述Schema 全局参数上下文主要用于获取从 createSchemaField 传入的参数。签名const SchemaOptionsContext injectISchemaFieldVueFactoryOptions(SchemaOptionsSymbol)ISchemaFieldVueFactoryOptions定义在 packages/vue/src/types/index.tsexport interface ISchemaFieldVueFactoryOptions Components extends SchemaVueComponents any { components?: Components scope?: any }即createSchemaField({ components, scope })的工厂参数。SchemaField的 setup 中会把options与 props 传入的components合并为optionsRef并provide(SchemaOptionsSymbol, optionsRef)SchemaField.ts。RecursionField通过inject(SchemaOptionsSymbol)拿到该上下文在schema.toFieldProps时把components用于解析x-component/x-decorator对应的注册组件scope用于表达式求值RecursionField.ts。ReactiveField渲染时也用FormPath.getIn(options?.components, field.componentType)从组件表中查找最终组件ReactiveField.ts。因此修改createSchemaField传入的components会全局影响所有 Schema 字段的组件解析这是 Formily Vue 组件注册体系的核心入口。典型消费场景自定义组件中组合使用六个注入项并非孤立存在实践中常组合使用。以官方封装 Hook 为参照import { useForm, useField, useFieldSchema } from formily/vue // 自定义字段组件内部 export default { name: MyField, setup() { const formRef useForm() // FormContext - RefForm const fieldRef useField() // FieldContext - RefGeneralField const schemaRef useFieldSchema() // SchemaContext - RefSchema return () { const form formRef.value const field fieldRef.value const schema schemaRef.value // 读取 field.display / field.value / schema[x-component-props] 等 // 调用 form.submit / form.setValuesIn 等 } }, }使用前提useForm必须在FormProvider :formform内useField/useFieldSchema必须在ReactiveField即任何字段组件或由SchemaField递归渲染的子树内。在FormProvider外调用useForm会得到默认空 Ref属于可容忍的降级行为而useField在非字段环境同样返回空 Ref需要自行判空。与其他包注入体系的对应关系注入体系在 Formily 的 React 与 Vue 实现中结构对齐formily/react 使用FormContext、FieldContext、SchemaMarkupContext、SchemaContext、SchemaExpressionScopeContext、SchemaOptionsContext这套同名字段。Vue 版本通过 vue-demi 同时支持 Vue 2Options API 渲染函数与 Vue 3例如ReactiveField中isVue2分支会额外用reaction包裹字段创建逻辑ReactiveField.ts这是响应式差异的兼容处理。理解本注入体系也就能快速迁移到 React 版本的相同心智模型。小结6 个注入项均定义于 packages/vue/src/shared/context.ts类型全部为RefTFormContext由FormProvider提供FieldContext由ReactiveField提供两者是表单/字段实例的获取入口SchemaMarkupContext、SchemaContext、SchemaExpressionScopeContext、SchemaOptionsContext由SchemaField/RecursionField/ExpressionScope协作提供支撑 Markup 收集、Schema 读取、表达式作用域与组件解析四条链路日常开发优先使用useForm、useField、useFieldSchema三个封装 Hook它们对缺失注入做了默认值降级需要深度定制如自定义 Schema 收集、局部表达式作用域时可直接inject对应 Symbol并参考 ExpressionScope 与 SchemaField 的实现模式。赞分享前端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 RecordsScope 详解在 JSON Schema 表达式中注入 $records 记录列表作用域Formily React RecordsScope 详解在 JSON Schema 表达式中注入 $records 记录列表作用域 导读 RecordsSc前端UI组件Formily ExpressionScope 组件详解为 JSON Schema 表达式注入局部作用域Formily ExpressionScope 组件详解为 JSON Schema 表达式注入局部作用域 ExpressionScope 是 Formily前端UI组件Formily RecordsScope 使用指南向 Schema 表达式注入 $records 记录列表作用域Formily RecordsScope 使用指南向 Schema 表达式注入 $records 记录列表作用域 RecordsScope 是 Formily前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

省级农业碳排放测度【2000-2024年】 含原始数据 计算过程
省级农业碳排放测度【2000-2024年】 含原始数据 计算过程

↓数据说明↓1.数据名称:省级农业碳排放测度2.原始数据来源:中国农村统计年Jian,eps数据库3.统计对象:31省(包含西藏自治区),分东中西部地区划分4.样本量:775条5.时间跨度&#xff1… · 2026/9/25 8:52:14

搞懂start用法,3个细节让你面试不再挂科
搞懂start用法,3个细节让你面试不再挂科

搞懂start用法,3个细节让你面试不再挂科 面试被问“线程启动原理”时卡壳,连 start() 和 run() 的区别都说不清,这简直是新手避坑路上的大忌。很多转岗开发者只记得调用 start()… · 2026/9/23 16:27:44

Vue项目中GSAP动画集成实战:原理、避坑与高阶交互动效
Vue项目中GSAP动画集成实战:原理、避坑与高阶交互动效

1. 为什么在Vue项目里用GSAP&#xff0c;而不是Vue内置的transition或动画系统&#xff1f;最近好几个团队朋友问我&#xff1a;“Vue自己就有<transition>、<transition-group>&#xff0c;还有v-enter/v-leave这些类名钩子&#xff0c;为啥还要额外引入GSAP&… · 2026/9/23 16:27:44

RisingWave 流式并行度统一配置设计解析:streaming_parallelism 参数语义、解析规则与旧参数迁移指南
RisingWave 流式并行度统一配置设计解析:streaming_parallelism 参数语义、解析规则与旧参数迁移指南

数据库流处理后端数据工程 【免费下载链接】risingwave Event streaming platform for agentic AI. Continuously ingest, transform, and serve event streams in real time, at scale. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ri/risingwave 点击查看 免费下载… · 2026/9/25 8:53:07

CTF-Wiki 内核堆利用:堆喷射(Heap Spray)实战解析——以 RWCTF2023 Digging into kernel 3 为例
CTF-Wiki 内核堆利用:堆喷射(Heap Spray)实战解析——以 RWCTF2023 Digging into kernel 3 为例

文档网络安全教程 【免费下载链接】ctf-wiki Come and join us, we need you! 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ct/ctf-wiki 点击查看 免费下载 本文是 CTF-Wiki 内核堆利用系列中针对 堆喷射&#xff08;heap spraying&#xff09; 手法的专题讲解。堆喷… · 2026/9/25 8:53:07

滋盟堂可信度高吗 值得信赖吗
滋盟堂可信度高吗 值得信赖吗

发展溯源&#xff1a;时光沉淀&#xff0c;深耕滋补行业的不变初心 行业浪潮下的起步锚点中国滋补文化传承千年&#xff0c;随着国民健康意识的提升&#xff0c;滋补消费从曾经的小众需求&#xff0c;逐渐走进大众日常生活。近二十年间&#xff0c;滋补品行业从渠道分散、标准模… · 2026/9/25 8:53:07

Hugo Blox Résumé 模板实战:用 blocks 组装在线简历 landing 页的完整配置指南
Hugo Blox Résumé 模板实战:用 blocks 组装在线简历 landing 页的完整配置指南

静态站点前端开发工具 【免费下载链接】kit &#x1f9f1; Describe your site, AI builds it, you own it as Markdown. Snap together Tailwind blocks like Lego — landing pages, blogs, portfolios, docs & more. No AI slop. Free to deploy anywhere &#x1f447;… · 2026/9/25 8:53:07

消费主义如何加剧现代人的孤独感
消费主义如何加剧现代人的孤独感

1. 消费主义时代的孤独悖论上周深夜刷购物App时&#xff0c;我突然意识到自己已经连续三晚在凌晨两点下单——从限量版球鞋到根本用不上的厨房神器。更讽刺的是&#xff0c;当快递堆满玄关时&#xff0c;那种熟悉的空虚感又回来了。这让我想起社会学教授常说的"孤独经济&q… · 2026/9/25 8:53:01

多目标点击率预测实战:七种用户行为建模与shared-bottom方案
多目标点击率预测实战:七种用户行为建模与shared-bottom方案

简介&#xff1a;面向微信视频号场景下的用户互动行为预测&#xff0c;这份2021年微信大数据挑战赛多目标预测方案聚焦读评论、点赞、点击头像、收藏、转发、发表评论、关注七种行为&#xff0c;构建基于用户行为数据的点击率预测模型&#xff0c;适合备赛学生、推荐系统学习者… · 2026/9/25 8:52:55

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码