
前端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点击查看免费下载ObjectField 是 formily/react 中用于将 formily/core 的 createObjectField 字段模型ViewModel与输入控件做绑定的桥接组件专治对象值动态增删属性这类复杂表单场景。读完本文你将掌握 ObjectField 的签名与核心属性、两种子组件组织方式自定义组件与 render props以及基于addProperty/removeProperty/existProperty实现动态键值编辑器如自定义 JSON 对象属性面板的完整实战方案。组件定位为什么需要 ObjectField在 formily 的字段体系中字段模型分为普通字段Field、对象字段ObjectField、数组字段ArrayField与虚字段VoidField等类型。ObjectField 对应值类型为对象的字段它的value是一个Recordstring, any因此天然适合表达一组由用户动态决定键名的属性集合例如环境变量配置、自定义扩展属性、KV 映射表等。从源码结构看ObjectField 是 formily/core 的ObjectField字段模型在 React 层的封装其实现位于 packages/react/src/components/ObjectField.tsxexport const ObjectField D extends JSXComponent, C extends JSXComponent( props: IFieldPropsD, C, ObjectFieldType ) { const form useForm() const parent useField() const field useAttach( form.createObjectField({ basePath: parent?.address, ...props }) ) return ( FieldContext.Provider value{field} ReactiveField field{field}{props.children}/ReactiveField /FieldContext.Provider ) }这段实现清晰展示了桥接链路useForm()获取当前FormProvider提供的表单实例useField()获取父级字段用于推导basePath通过form.createObjectField({ basePath: parent?.address, ...props })创建或复用对象字段模型并将其挂载到表单字段图上将字段模型放入FieldContext.Provider供内部嵌套的Field通过useField读取用 ReactiveField 包裹渲染保证字段状态变化时响应式更新 UI。在 formily/core 中createObjectField会保证对象字段的默认值为{}而非undefined相关逻辑见 packages/core/src/models/Form.tscreateObjectField Decorator, Component(props: IFieldFactoryProps...) { const address FormPath.parse(props.basePath).concat(props.name) const identifier address.toString() if (!identifier) return if (!this.fields[identifier] || this.props.designable) { batch(() { new ObjectField(address, { ...props, value: isObj(props.value) ? props.value : {}, }, this, this.props.designable) }) this.notify(LifeCycleTypes.ON_FORM_GRAPH_CHANGE) } return this.fields[identifier] }注意isObj(props.value) ? props.value : {}这一兜底逻辑即使不传value字段值也会被规范化为对象这正是后续Object.keys(field.value || {})遍历安全的前提。签名与核心属性type ObjectField React.FCReact.PropsWithChildrenIFieldFactoryPropsObjectField 的 Props 继承自IFieldFactoryProps定义于 packages/core/src/types.tsexport interface IFieldFactoryProps Decorator extends JSXComponent, Component extends JSXComponent, TextType any, ValueType any extends IFieldPropsDecorator, Component, TextType, ValueType { name: FormPathPattern // 必填字段路径决定字段在表单值树中的位置 basePath?: FormPathPattern // 可选基准路径默认取父级字段地址 }在此基础上React 层的 IFieldProps 补充了三个渲染相关属性属性类型说明nameFormPathPattern必填字段在表单值中的路径如object、a.bbasePathFormPathPattern可选字段的基准路径默认自动取父级字段地址childrenRenderPropsChildrenField可传普通 ReactNode也可传(field, form) ReactNode函数render propsdecorator[] \| [D] \| [D, props]装饰器组件及其属性如 FormItemcomponent[] \| [C] \| [C, props]输入组件及其属性如 Input也可不传、纯靠 children 组织 UI使用警示使用 ObjectField 时必须传name属性同时推荐用 render props 形式组织子组件这样能直接拿到字段模型做动态控制这也是下文两个用例的共同基础。自定义组件用例用 observer 订阅字段模型第一种组织方式是自定义组件 useField。自定义组件通过observer包裹后即可像订阅普通响应式数据一样订阅字段模型的状态变化。完整用例来自 ObjectField.zh-CN.mdimport React from react import { createForm, ObjectField as ObjectFieldType } from formily/core import { FormProvider, Field, ObjectField, useField, observer, } from formily/react import { Input, Button, Space } from antd const form createForm() const ObjectComponent observer(() { const field useFieldObjectFieldType() return ( div {Object.keys(field.value || {}).map((key) ( div key{key} style{{ display: flex-block, marginBottom: 10 }} Space Field name{key} component{[Input, { placeholder: key }]} / Button onClick{() { field.removeProperty(key) }} Remove /Button /Space /div ))} /div Space Field namepropertyName basePath{} required component{[Input, { placeholder: Property Name }]} / Button onClick{() { const name form.values.propertyName if (name !form.existValuesIn(${field.path}.${name})) { field.addProperty(name, ) form.deleteValuesIn(propertyName) } }} Add /Button /Space / ) }) export default () ( FormProvider form{form} ObjectField nameobject component{[ObjectComponent]} / /FormProvider )用例解读useFieldObjectFieldType()在FieldContext内读取当前对象字段模型类型标注为 core 层的ObjectField从而获得addProperty等扩展方法的类型提示渲染已有属性Object.keys(field.value || {})遍历对象键为每个键内嵌一个普通Fieldname{key}相对于当前对象字段路径并配一个 Remove 按钮动态添加属性表单里放一个临时输入框propertyName注意basePath{}使其脱离对象字段路径、挂在表单顶层点击 Add 时读取form.values.propertyName用field.addProperty(name, )写入新属性再用form.deleteValuesIn(propertyName)清空临时输入去重校验form.existValuesIn(${field.path}.${name})用于判断目标路径是否已存在值避免重复添加同名属性observerObjectComponent必须用observer包裹否则新增/删除属性导致field.value变化时组件不会重新渲染。Render Props 用例不写自定义组件也能动态控制如果不想额外定义组件可以直接把 children 写成函数函数参数即字段模型field。此时无需observer、useField因为 render props 本身就是把字段模型作为渲染数据直接传入。完整用例import React from react import { createForm } from formily/core import { FormProvider, Field, ObjectField } from formily/react import { Input, Button, Space } from antd const form createForm() export default () ( FormProvider form{form} ObjectField nameobject {(field) { return ( div {Object.keys(field.value || {}).map((key) ( div key{key} style{{ display: flex-block, marginBottom: 10 }} Space Field name{key} component{[Input, { placeholder: key }]} / Button onClick{() { field.removeProperty(key) }} Remove /Button /Space /div ))} /div Space Field namepropertyName basePath{} required component{[Input, { placeholder: Property Name }]} / Button onClick{() { const name form.values.propertyName if (name !form.existValuesIn(${field.path}.${name})) { field.addProperty(name, ) form.deleteValuesIn(propertyName) } }} Add /Button /Space / ) }} /ObjectField /FormProvider )与自定义组件方案的取舍两种方案的核心逻辑遍历、增删属性完全一致区别在于组织方式自定义组件方案适合属性面板逻辑复杂、需要复用的场景。组件独立成函数配合observer获得响应式订阅后续可抽成通用组件Render Props 方案适合简单、一次性的动态对象编辑内联书写、无需额外组件定义代码更紧凑。从 ReactiveField 的实现看两种方式最终汇合到同一条渲染路径const renderChildren (children, field?, form?) isFn(children) ? children(field, form) : childrenReactiveField会检测 children 是否为函数若是函数则以(field, form)为参数调用render props 分支否则直接作为普通节点渲染自定义组件分支。两种分支共享后续的decorator、component、display非visible不渲染、patterndisabled/readOnly 映射等统一渲染逻辑。源码深处addProperty 与 removeProperty 的实现原理用例中反复使用的三个方法定义在 core 层的字段模型 packages/core/src/models/ObjectField.tsaddProperty (key: string, value: any) { this.form.setValuesIn(this.path.concat(key), value) this.additionalProperties.push(key) return this.onInput(this.value) } removeProperty (key: string) { this.form.deleteValuesIn(this.path.concat(key)) this.additionalProperties.splice(this.additionalProperties.indexOf(key), 1) return this.onInput(this.value) } existProperty (key: string) { return this.form.existValuesIn(this.path.concat(key)) }三个方法的语义与 core 层 ObjectField 模型文档 一致方法签名行为addProperty(key: FormPathPattern, value: any) Promisevoid向对象写入属性setValuesIn并触发onInputremoveProperty(key: FormPathPattern) Promisevoid删除对象属性deleteValuesIn并触发onInputexistProperty(key: FormPathPattern) boolean判断对象中是否存在指定属性值得关注的是模型构造阶段的自动清理机制ObjectField.tsprotected makeAutoCleanable() { this.disposers.push( reaction( () Object.keys(this.value || {}), (newKeys) { const filterKeys this.additionalProperties.filter( (key) !newKeys.includes(key) ) cleanupObjectChildren(this, filterKeys) } ) ) }该模型通过reaction监听对象键集合的变化当某个通过addProperty动态添加的属性键从值中消失被删除时会同步清理该键对应的子字段模型防止字段图Form Graph中残留孤立字段导致状态不同步。这意味着通过addProperty/removeProperty增删属性时子字段会被正确创建/销毁直接通过form.setValuesIn/form.deleteValuesIn修改值也能触发同样的清理逻辑保证字段图与值保持一致。使用注意事项与最佳实践name必须传ObjectField 的name是必填项类型层面强制name: FormPathPattern缺失时字段地址无法解析、字段无法挂载到表单优先 render props 组织子组件把字段模型作为 children 函数的入参能在声明式 JSX 中直接调用addProperty等方法避免额外编写observer组件区分对象字段与普通字段若值结构固定如一个已知 schema 的对象用Field JSON Schema 即可只有当键名需要运行时动态增删时才需要 ObjectField其价值在于addProperty/removeProperty对子字段图的自动维护临时输入框用basePath{}隔离动态添加属性时需要一个属性名输入框将其basePath设为空串可避免它被错误地嵌套进对象字段的值路径配合响应式渲染若采用自定义组件方案务必用observer包裹render props 方案则由 ReactiveField 内置的响应式机制保证更新无需手动处理。小结ObjectField 是 formily 对象类型字段在 React 层的标准桥接组件它把 core 层的对象字段模型通过FieldContext注入到子组件树并借助ReactiveField完成响应式渲染。配合addProperty/removeProperty/existProperty三个扩展方法与自动清理机制可以高效实现属性动态增删的复杂编辑场景。本文的两个完整用例自定义组件 render props均可直接复制运行适合作为自定义 KV 编辑器、动态扩展属性面板等功能的基础模板。赞分享前端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 ObjectField 组件全解析动态对象结构表单的 ViewModel 桥接实践Formily Vue ObjectField 组件全解析动态对象结构表单的 ViewModel 桥接实践 ObjectField 是 Formily Vue前端UI组件Formily Core ObjectField 模型完全指南对象字段的动态属性增删与状态管理Formily Core ObjectField 模型完全指南对象字段的动态属性增删与状态管理 ObjectField 是 Formily 核心模型体系中专门前端UI组件Formily React ArrayField 组件完全指南数组型字段的 ViewModel 绑定与增删改排实战Formily React ArrayField 组件完全指南数组型字段的 ViewModel 绑定与增删改排实战 ArrayField 是 Formily前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考