尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Formily Vue 自定义组件开发:useField Hook 读取与操作字段状态完全指南

发布时间:2026/9/24 7:28:10

资讯中心
01
ARTICLE

Formily Vue 自定义组件开发:useField Hook 读取与操作字段状态完全指南

Formily Vue 自定义组件开发:useField Hook 读取与操作字段状态完全指南
前端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点击查看免费下载导读useField是 Formily Vue 体系中面向自定义组件开发的核心 Hook它让任意位于 Field 组件子树内的自定义组件都能直接读取当前字段的属性、值、校验状态并主动调用字段模型的方法进行状态操作。本文基于 formily 仓库中 packages/vue/docs/api/hooks/use-field.md 的官方文档并结合formily/vue的实际源码与测试用例深入讲解useField的签名、工作原理、类型检查器配合方案与响应式注意点读完即可在自己的自定义组件中安全、高效地使用useField。一、useField 是什么用途与适用场景useField主要用在自定义组件内用于完成两类核心工作读取当前字段属性例如读取字段的value、display、pattern、path、address、校验反馈信息等操作字段状态例如调用字段的setValue、setState、setDisplay、setPattern等方法主动驱动字段模型变化。它在所有 Field 组件的子树内都能使用——这里的 Field 组件是广义的包括 Field、ObjectField、ArrayField、VoidField 等。以 RecursionField 为例它在setup中通过const parentRef useField()获取父级字段用于计算子字段的basePath这正是Field 子树内可用的典型体现。注意useField拿到的是GeneralField通用字段模型它涵盖了 Field、ArrayField、ObjectField、VoidField 四类字段的公共能力。如果需要针对不同类型的字段做差异化处理请配合 Type Checker类型检查器使用下文第五节详解。二、签名与类型定义官方文档给出的签名为interface useField { (): RefField }对照仓库中 packages/vue/src/hooks/useField.ts 的真实实现签名更为精确import { 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 }关键点说明泛型参数T默认返回RefGeneralField。你可以显式传入更具体的字段类型例如useFieldFieldType()这在 packages/vue/src/tests/field.spec.ts 的useFormEffects测试用例中就有实际应用返回值是RefT即一个 Vue 响应式引用访问时需要通过.value解包例如fieldRef.value.setValue(123)返回inject(FieldSymbol, ref())从依赖注入容器中取出当前字段引用若取不到则回退为空的ref()保证在非字段上下文中调用也不会抛错。这里涉及的FieldSymbol定义于 packages/vue/src/shared/context.tsexport const FieldSymbol: InjectionKeyRefGeneralField Symbol(field)useField的全部导出由 packages/vue/src/hooks/index.ts 统一聚合与useForm、useFormEffects、useFieldSchema、useParentForm并列导出。三、工作原理provide / inject 注入链useField之所以能在所有 Field 子树内使用依赖 Vue 的依赖注入机制注入链如下提供方字段渲染组件 ReactiveField 在创建字段模型后调用provide(FieldSymbol, fieldRef)把当前字段的Ref提供给整棵子树消费方任意子组件包括自定义组件、RecursionField、ReactiveField自身通过inject(FieldSymbol, ...)拿到最近的父级字段嵌套取值由于inject遵循就近原则在多级嵌套字段结构中每个useField()拿到的一定是离自己最近的祖先字段。例如 ReactiveField.ts 中const parentRef useField()用于读取父字段地址parentRef.value?.address再结合basePath创建子字段从而自动形成完整的字段地址链。从源码结构看Field/ObjectField/ArrayField/VoidField组件最终都会渲染为ReactiveField如 Field.ts 所示无论 Vue 2 还是 Vue 3 分支都指向ReactiveField因此这一注入机制对四类字段统一生效。四、基本用法在自定义组件中读取与操作字段4.1 读取字段属性的最小示例参考 packages/vue/src/tests/field.spec.ts 中Input组件的写法这是最经典的useField用法import { defineComponent, h } from vue import { useField } from formily/vue const Input defineComponent({ props: [value], setup(props, { attrs, listeners }) { const fieldRef useField() return () { const field fieldRef.value return h(input, { class: test-input, attrs: { ...attrs, value: props.value, data-testid: field.path.toString(), // 读取字段路径 }, on: { ...listeners, input: listeners.change, }, }) } }, })在这个例子中field.path.toString()直接读出了字段在表单中的路径如cc.mm测试断言getByTestId(cc.mm)也能证明嵌套字段路径的正确性。除了path通过GeneralField你还能读取field.value字段当前值field.display/field.pattern字段的显示模式与交互模式editable/disabled/readOnly/readPrettyfield.valid/field.errors/field.feedbacks字段校验状态与反馈信息field.address/field.path字段在表单树中的地址与路径field.form所属表单实例。其中display、pattern的取值与继承逻辑定义于 packages/core/src/models/BaseField.ts它们会向上级联父字段与表单的默认值例如默认display visible、pattern editable这解释了为什么字段模型具有子随父动的联动表现。4.2 操作字段状态useField拿到的字段模型本身是响应式模型可直接调用其方法操作状态例如const fieldRef useFieldFieldType() // 设置值 fieldRef.value.setValue(123) // 批量修改状态 fieldRef.value.setState((state) { state.value 123 state.pattern readPretty }) // 切换显示/模式 fieldRef.value.setDisplay(hidden) fieldRef.value.setPattern(disabled)值得注意的是字段模型的setDisplay/setPattern同样定义于 BaseField.ts其实现会在设置自身selfDisplay/selfPattern的同时维护与表单全局状态的联动关系。4.3 在自定义组件中使用泛型约束由于useField默认返回GeneralField当你确定组件只会挂载在普通Field下时可以传入更精确的类型以获得类型提示import { Field as FieldType } from formily/core import { useField } from formily/vue const fieldRef useFieldFieldType()这一写法在 field.spec.ts 的useFormEffects测试中被实际使用并通过isVoidField(target)守卫后调用fieldRef.value.setValue(...)。五、GeneralField 与 Type Checker按类型差异化处理useField返回的是GeneralField它只保证四类字段Field、ArrayField、ObjectField、VoidField的公共能力。若需按类型做差异化逻辑官方文档明确建议配合Type Checker使用。Type Checker 位于 packages/core/src/shared/checkers.ts核心导出包括isFieldisArrayFieldisObjectFieldisVoidField典型写法import { isVoidField, isField } from formily/core import { useField } from formily/vue const fieldRef useField() // 只对非 VoidField 做值操作 if (!isVoidField(fieldRef.value)) { fieldRef.value.onInput(new value) } // 只对普通 Field 做处理 if (isField(fieldRef.value)) { fieldRef.value.setValue(123) }在 RecursionField.ts 中schema 的typeobject/array/void及其他被分别路由到ObjectField、ArrayField、VoidField和Field这与 Type Checker 的分类体系一一对应而在 ReactiveField.ts 渲染逻辑中也大量使用isVoidField(field)判断是否注入value、disabled等属性——例如 VoidField 不参与onInput值写入普通 Field 则会根据pattern disabled || pattern readPretty自动设置disabled。这些实现细节印证了先做类型判断再做字段操作的工程惯例。六、响应式要点必须用 observer 包裹自定义组件官方文档给出了明确警告如果要在自定义组件内使用useField并响应字段模型变化需要使用observer包裹自定义组件。原因在于useField返回的fieldRef是一个普通的Ref由shallowRef创建字段模型内部的响应式变化并不会自动触发自定义组件的重渲染。只有通过 Formily 的响应式观察器observer来自formily/reactive-vue源码位于 packages/reactive-vue/src/observer/包裹组件组件才会在字段模型的value、display、pattern等状态变化时自动更新。正确的做法import { observer } from formily/reactive-vue import { defineComponent, h } from vue import { useField } from formily/vue const CustomField observer( defineComponent({ setup() { const fieldRef useField() return () { const field fieldRef.value // 字段 value 变化时此处会自动重新渲染 return h(div, {}, [String(field.value)]) } }, }) )反向印证在 ReactiveField.ts 中字段渲染组件本身就用observer({...})包裹因此字段模型的display、value变化能够驱动表单 UI 实时刷新而自定义组件若不包裹observer则只能读到初始时的字段状态无法随模型变化更新。测试方面field.spec.ts 的useFormEffects用例中CustomField组件在onFieldChange回调里调用fieldRef.value.setValue(target.value)随后waitFor断言custom-value节点的文本更新为123——这一过程正是字段状态变化 → 组件响应式更新的完整闭环验证。七、进阶useField 与其他 Hook 的组合7.1 与 useParentForm 组合useField是useParentForm的底层依赖。查看 packages/vue/src/hooks/useParentForm.ts 的实现export const useParentForm (): RefForm | ObjectField { const field useField() const form useForm() const findObjectParent (field: GeneralField) { if (!field) return form.value if (isObjectField(field)) return field return findObjectParent(field?.parent) } return computed(() findObjectParent(field.value)) }可见useParentForm通过useField()拿到当前字段再沿field.parent向上查找最近的 ObjectField找不到则回退到 Form 实例——这是字段子树内可用与 Type Checker 相结合的一个经典封装案例也是自定义组件内向上找容器/找表单的推荐手段。7.2 与 useFormEffects 组合在自定义组件中useField常与useFormEffects搭配实现字段联动。参考 field.spec.ts 中的用例组件通过useFormEffects订阅onFieldChange(aa, [value], ...)在回调里读取目标字段的新值并写入当前字段实现跨字段的值同步。这种方式将字段订阅与字段操作解耦是动态表单联动的最佳实践之一。八、适用前提与使用限制必须位于字段子树内useField依赖provide注入只有在FormProvider→ 各类 Field 组件形成的嵌套结构内才能拿到字段脱离字段上下文时它返回空Refref()的默认回退拿到的是 GeneralField需要具体类型能力如数组字段的move/remove、对象字段的setValues等时请配合 Type Checker 收窄类型响应式更新依赖 observer不包裹observer时组件不会随字段模型变化而重渲染Vue 2 / Vue 3 双兼容formily/vue通过vue-demi实现跨版本支持useField在两种环境中均可直接使用见 useField.ts 对vue-demi的引入以及 ReactiveField.ts 中针对 Vue 2 的createFieldInVue2兼容逻辑。结语useField虽只有短短几行实现却是打通自定义组件 ↔ 字段模型的关键桥梁。理解其inject/provide注入机制、Ref返回值约定、Type Checker 类型分派与observer响应式约束就能在 Formily Vue 生态中自由构建高性能的自定义字段组件。建议进一步阅读 useFieldSchema、useForm、useParentForm 等相邻 Hook 文档以及 packages/vue/src/tests/field.spec.ts 中的完整测试用例以获得更系统的掌握。赞分享前端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 useField Hook 完全指南在自定义组件中读取字段模型与状态Formily React useField Hook 完全指南在自定义组件中读取字段模型与状态 导读 useField 是 Formily React 体系前端UI组件Formily React 中 useFieldSchema Hook 完全指南在自定义组件中读取当前字段 SchemaFormily React 中 useFieldSchema Hook 完全指南在自定义组件中读取当前字段 Schema 导读 useFieldSchema前端UI组件Formily Vue useFieldSchema 完全指南在自定义组件中读取当前字段的 Schema 信息Formily Vue useFieldSchema 完全指南在自定义组件中读取当前字段的 Schema 信息 导读 useFieldSchema 是 For前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。