Formily Vue 自定义组件中的 RecursionField 自增列表递归实战:从 useField 到递归渲染
前端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 实现formily/vue中一个关键 API——RecursionField自增列表递归。它解决的核心问题是当内置的数组类组件如ArrayTable、ArrayCards无法满足业务形态时如何在自定义组件内部拿到「当前字段实例」和「字段 Schema」并手动驱动 JSON Schema 的递归渲染从而自由定制自增/自减列表的 UI。读完本文你将掌握RecursionField的完整属性签名、它在SchemaField内部的渲染原理以及一个可直接复制的自增列表递归自定义组件实现含完整源码与关键行解析。一、RecursionField 是什么在 Formily 的架构里SchemaField负责把 JSON Schema 转换成真实的表单字段树而这个转换动作的核心执行者正是RecursionField。它本身是一个独立的递归渲染组件可以脱离SchemaField单独使用——这给了开发者一种自绘递归的能力你可以用任意 UI 布局去包裹 Schema 中定义好的字段节点再通过RecursionField把子节点渲染出来。官方对它的定位是见 RecursionField 组件文档递归渲染组件主要基于 JSON-Schema 做递归渲染它是 SchemaField 组件内部的核心渲染组件。它可以在自定义组件中使用用于实现具有递归渲染能力的自定义组件。而本文关联的 自增列表递归文档 则给出了它的典型业务场景——自增列表Array使用useField和useFieldSchema来获取当前字段上下文中的字段实例和字段 schema。一句话总结使用模型在自定义组件内部用useField()拿到字段实例数组值、增删方法用useFieldSchema()拿到当前节点的 Schema然后把 Schema 的items节点交给RecursionField渲染从而实现完全可控的列表 UI。二、属性签名IRecursionFieldProps 全解虽然自增列表文档本身没有列出属性表但其签名定义在同目录的 recursion-field.md 中是理解递归渲染的关键完整如下interface IRecursionFieldProps { schema: Schema // schema 对象 name?: string // 路径名称 basePath?: FormPathPattern // 基础路径 onlyRenderProperties?: boolean // 是否只渲染 properties onlyRenderSelf?: boolean // 是否只渲染自身不渲染 properties mapProperties?: (schema: Schema, name: string) Schema // schema properties 映射器主要用于改写 schema filterProperties?: (schema: Schema, name: string) boolean // schema properties 过滤器被过滤掉的 schema 节点不会被渲染 } type RecursionField Vue.ComponentIRecursionFieldProps在 Vue 组件层面的 props 声明见 RecursionField 源码schema为必填项name支持String与Number数组下标即数字路径onlyRenderProperties与onlyRenderSelf均为 Boolean。各属性作用说明属性默认行为说明schema必填要递归渲染的 Schema 节点可以是独立对象字面量也可以是SchemaField内部取到的 Schema 实例name无字段路径名称传入后表示渲染一个有路径的字段节点不传时只渲染properties结构用于布局basePath父字段地址字段挂载的基础路径。特殊地当onlyRenderProperties为真时默认会拼接name作为基础路径onlyRenderPropertiesfalse只渲染当前 schema 的properties不创建当前字段实例常用于纯容器组件onlyRenderSelffalse只渲染自身字段完全跳过properties的渲染mapProperties无渲染前对每个子 property 做改写映射filterProperties无返回false的 property 节点将被跳过不参与渲染三、源码原理RecursionField 如何驱动递归要真正用好这个组件需要理解它的渲染决策。阅读 RecursionField.ts 实现 可以归纳出以下关键机制1. Schema 的响应式构造组件通过markRaw(new Schema(schemaProp))将传入的 props.schema 构造为Schema实例源码 L49-L51并用computed包裹使得 Schema 变化时能重新生成字段属性toFieldProps。这意味着你传给RecursionField的 schema 可以是动态计算出来的。2. 按 Schema type 分发渲染核心渲染函数源码 L133-L190按照 Schema 的type走四条分支object渲染为ObjectField并把子 properties 作为插槽传入array渲染为ArrayField自增列表的核心字段模型void渲染为VoidField无数据占位字段常用于布局其他string/number等渲染为普通Field。如果name不合法!isValid(props.name)则退化为只渲染 properties 结构不创建字段实例源码 L134-L135。3. properties 的递归展开generateSlotsByProperties源码 L79-L131会通过Schema.getOrderProperties获取有序的 properties 列表对每个子节点依次执行mapProperties映射与filterProperties过滤然后再次递归地调用RecursionField自身渲染子节点——这就是递归二字的来源。同时它支持x-slot插槽名分发把子节点渲染进对应的具名插槽。4. basePath 的智能推导getBasePath源码 L66-L71的逻辑是若未显式传basePath则默认取父字段的地址当onlyRenderProperties为真时会额外拼接name保证嵌套路径正确。从源码结构可以推断RecursionField是SchemaField内部的渲染引擎对外暴露出来是为了让自定义组件复用同一套字段创建与递归机制从而保证自定义组件的字段行为与SchemaField完全一致。四、实战自增列表递归自定义组件下面是 官方用例 demo 的完整实现。它定义了一个名为ArrayItems的自定义组件渲染输入框 Remove 按钮的列表并提供 Add 按钮动态追加行template FormProvider :formform SchemaField SchemaArrayField namecustom x-componentArrayItems SchemaObjectField SchemaStringField nameinput x-componentInput / /SchemaObjectField /SchemaArrayField /SchemaField /FormProvider /template script import { defineComponent, h } from vue/composition-api // or import { defineComponent, h } from vue if using vue3 import { Input, Button, Space } from ant-design-vue import { createForm } from formily/core import { FormProvider, createSchemaField, RecursionField, useField, useFieldSchema, } from formily/vue import { observer } from formily/reactive-vue import ant-design-vue/dist/antd.css const ArrayItems observer( defineComponent({ setup() { const fieldRef useField() const schemaRef useFieldSchema() return () { const field fieldRef.value const schema schemaRef.value const items field.value?.map((item, index) { return h(div, { key: item.id, style: { marginBottom: 10px } }, [ h(Space, [ // params of render function is different in vue3 h(RecursionField, { props: { schema: schema.items, name: index }, }), h(Button, { on: { click: () field.remove(index) } }, [ Remove, ]), ]), ]) }) const button h( Button, { on: { click: () field.push({ id: Date.now() }) } }, [Add] ) return h(div, [items, button]) } }, }) ) const { SchemaField, SchemaStringField, SchemaArrayField, SchemaObjectField } createSchemaField({ components: { ArrayItems, Input, }, }) export default { components: { FormProvider, SchemaField, SchemaStringField, SchemaArrayField, SchemaObjectField, }, data() { return { form: createForm(), } }, } /script逐段拆解这个 demo 的关键点① Schema 侧外层用SchemaArrayFieldtypearrayx-component 指向自定义组件ArrayItems子节点是一个SchemaObjectField其下再挂SchemaStringField输入框。也就是说每一行数组项是一个对象对象里含一个input字段。② 获取上下文useField / useFieldSchemauseField()返回当前字段实例即custom数组字段提供.value数组、push、remove等方法useFieldSchema()返回当前节点的 Schema 实例。它们的实现本质是 Vue 的依赖注入——见 useField 源码 与 useFieldSchema 源码分别注入FieldSymbol与SchemaSymbol上下文。这与官方文档使用 useField 和 useFieldSchema 来获取当前字段上下文中的字段实例和字段 schema的描述完全对应。③ 递归渲染数组项对数组的每一项用h(RecursionField, { props: { schema: schema.items, name: index } })把schema.items数组项 Schema和index数组下标作为路径 name交给 RecursionField让它去创建ObjectField并递归渲染内部的input字段。这正是自增列表递归的核心动作。④ 增删行field.push({ id: Date.now() })追加行push 的对象会作为该行字段的数据初始值field.remove(index)删除指定行。配合observer包裹组件字段值变化会驱动列表重新渲染。⑤ 响应式组件用formily/reactive-vue的observer包裹保证 field 值变化增删行、输入时组件自动更新。五、补充场景在纯自定义容器中渲染独立 Schema除了数组项递归RecursionField还可以在自定义组件里渲染一段完全独立的 Schema 对象。官方另一个 demo 展示了这种用法通过x-component-props传入一段对象字面量 schema自定义组件用onlyRenderProperties: true只渲染其 propertiesSchemaObjectField namecustom x-componentCustom :x-component-props{ schema: { type: object, properties: { input: { type: string, x-component: Input, }, }, }, } /const Custom { functional: true, render(h, { props }) { return h(RecursionField, { props: { name: props.name, schema: props.schema, onlyRenderProperties: true, }, }) }, }这里onlyRenderProperties: true表示不创建custom自身的字段实例只把 properties 里的input渲染出来因此适合做透明容器型的自定义组件。从 RecursionField 源码 可以看到当onlyRenderProperties为真时组件直接返回generateSlotsByProperties()的渲染结果不实例化字段。六、与 SchemaField 的关系与选用建议关系SchemaField是递归渲染的入口RecursionField是递归渲染的引擎。SchemaField内部正是通过RecursionField对根 Schema 做递归展开从而得到完整字段树开发者把RecursionField暴露出来是为了在自定义组件中复用同一套机制。选用建议常规业务直接使用内置数组组件ArrayTable、ArrayCards、ArrayCollapse、ArrayTabs等见 antd 文档无需接触RecursionField当内置组件无法满足布局要求例如需要完全自定义的行内结构、按钮位置、行间距时参考本文第四节用useFielduseFieldSchemaRecursionField自绘列表需要渲染独立 Schema 片段时参考第五节配合onlyRenderProperties/mapProperties/filterProperties精确控制渲染内容。七、小结RecursionField是 Formily Vue 递归渲染体系的核心 API。本文从官方文档的自增列表递归用例出发完整覆盖了它的属性签名、源码渲染决策按 schema.type 分发、properties 递归展开、basePath 推导、两个可直接运行的实战 demo以及底层useField/useFieldSchema的注入机制。掌握它意味着你可以跳出内置组件的边界用任意 UI 结构承载 Formily 的 JSON Schema 字段树——这正是 Formily 动态表单能力的开放接口所在。赞分享前端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 RecursionField 递归渲染组件完全指南基于 JSON-Schema 的自定义递归组件实现Formily Vue RecursionField 递归渲染组件完全指南基于 JSON Schema 的自定义递归组件实现 导读 RecursionFiel前端UI组件Formily React 递归渲染组件 RecursionField 全面解析原理、API 与自定义递归组件实战Formily React 递归渲染组件 RecursionField 全面解析原理、API 与自定义递归组件实战 导读 RecursionField 是 F前端UI组件Formily 递归渲染核心组件 RecursionField 完全指南基于 JSON Schema 的自定义组件递归方案Formily 递归渲染核心组件 RecursionField 完全指南基于 JSON Schema 的自定义组件递归方案 导读 RecursionField前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

cytoscape.js 元素移除详解:cy.remove() 的用法、联动删除机制与恢复原理

cytoscape.js 元素移除详解:cy.remove() 的用法、联动删除机制与恢复原理

数据可视化 【免费下载链接】cytoscape.js Graph theory (network) library for visualisation and analysis 项目地址: https://gitcode.com/gh_mirrors/cy/cytoscape.js 点击查看 免费下载 导读 本文基于 cytoscape.js 官方文档中关于 core 级 remove 方法的说明…

2026/9/24 6:47:40 阅读更多 →
RL-赵-(六):随机逼近与随机梯度下降02-2:Robbins-Monro(RM)算法【wₖ₊₁=wₖ-αₖĝ(wₖ,ηₖ)】【SA领域的开创性工作】

RL-赵-(六):随机逼近与随机梯度下降02-2:Robbins-Monro(RM)算法【wₖ₊₁=wₖ-αₖĝ(wₖ,ηₖ)】【SA领域的开创性工作】

2、Robbins-Monro(RM)算法 Robbins-Monro(RM)算法: wk+1 = wk − ak g~(wk,ηk ),k = 1,2,3,... \begin{aligned}w_{k+1}\:=\:w_k\:-\:a_k\:\tilde{g}(w_k,\eta_k\:),k\:=\:1,2,3,...\end{aligned} wk+1​=wk​−ak​g~​(wk​,ηk​),k=1,2,3,...​ 其中 wkw_kwk…

2026/9/24 6:47:40 阅读更多 →
实习多平台和传统招聘平台有什么区别?4个维度对比

实习多平台和传统招聘平台有什么区别?4个维度对比

实习多平台和传统招聘平台有什么区别?这是很多学生找实习时最常问的问题。实习多平台和传统招聘平台有什么区别,简单说就是"垂直vs综合"“AI匹配vs关键词搜索”“小程序vsAPP”“学生免费vs可能收费”。实习多平台和传统招聘平台有什么区别&am…

2026/9/24 6:47:39 阅读更多 →

最新新闻

电脑故障处理打印版:一张纸搞定蓝屏、C盘满、重装排查

电脑故障处理打印版:一张纸搞定蓝屏、C盘满、重装排查

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

2026/9/24 7:32:07 阅读更多 →
ESP32-S3-BOX-3实战:智能语音与物联网联动开发指南

ESP32-S3-BOX-3实战:智能语音与物联网联动开发指南

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

2026/9/24 7:32:07 阅读更多 →
EMQX 升级 gen_rpc 3.5.1:根治节点不可达时的 Crash 日志长尾与 `failed_to_connect_server` 刷屏

EMQX 升级 gen_rpc 3.5.1:根治节点不可达时的 Crash 日志长尾与 `failed_to_connect_server` 刷屏

后端物联网消息队列通信 【免费下载链接】emqx The most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles 项目地址: https://gitcode.com/gh_mirrors/em/emqx 点击查看 免费下载 导读 本文围绕 EMQX 官方变更记录 fix-16453.en.md …

2026/9/24 7:32:07 阅读更多 →
Arm Development Studio双平台安装避坑指南

Arm Development Studio双平台安装避坑指南

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

2026/9/24 7:31:07 阅读更多 →
OpenStack Nova实例生命周期深度解析:Start、Reboot与Lock操作实战

OpenStack Nova实例生命周期深度解析:Start、Reboot与Lock操作实战

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

2026/9/24 7:31:06 阅读更多 →
轻量级键盘检测工具:基于Raw Input的精准状态诊断

轻量级键盘检测工具:基于Raw Input的精准状态诊断

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

2026/9/24 7:31:06 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →