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

Formily Core Query 对象完全指南:字段查询 API 的方法签名、底层实现与实战用法

发布时间:2026/9/23 14:26:30 来源:云帆数科 栏目:资讯中心
Formily Core Query 对象完全指南:字段查询 API 的方法签名、底层实现与实战用法
Formily Core Query 对象完全指南字段查询 API 的方法签名、底层实现与实战用法【免费下载链接】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本文围绕 Query.md 文档展开系统讲解 Formily 核心包formily/core中 Query 查询对象的全部 APItake、map、forEach、reduce、get、getIn、value、initialValue的签名与语义并结合 Query.ts 源码剖析其匹配原理、相对路径解析逻辑以及 Form/Field 中query方法的真实调用场景。一、导读Query 是什么在 Formily 中Query是由Form实例或Field实例上的query(pattern)方法返回的一个查询结果对象。它封装了一次按路径模式检索字段节点的结果集并提供一组与数组操作同构的方法take/map/forEach/reduce以及便捷的状态读取方法get/getIn/value/initialValue让开发者可以用声明式的路径模式FormPathPattern批量定位字段并读取其状态。理解 Query 是掌握 Formily 核心包字段操作的基础Form 内部的clearErrors、clearWarnings、queryFeedbacks、clearFormGraph等内置能力全部建立在 Query 之上。读完本文你将掌握 Query 对象每个方法的调用签名、返回值语义、与FormPathPattern的配合方式以及它在 Formily 源码中的实际工作链路。二、Query 的诞生从query()方法说起Query 对象本身并不需要手动new而是通过两个入口获取Form实例上的query(pattern: FormPathPattern): Query详见 Form.mdField实例含Field、ArrayField、ObjectField、VoidField即GeneralField上的query(pattern: FormPathPattern | RegExp): Query详见 Field.md。从源码看两个入口最终都构造了同一个Query类Query.ts// Form 侧Form.ts#L513-L519 query (pattern: FormPathPattern): Query { return new Query({ pattern, base: , form: this, }) } // Field 侧BaseField.ts#L320-L326 query (pattern: FormPathPattern | RegExp) { return new Query({ pattern, base: this.address, form: this.form, }) }两者唯一的差异在于构造参数baseForm.query传入base: 查询基准是表单根路径Field.query传入base: this.address即以当前字段地址为基准进行相对路径查询因此可以在一个字段内部查询它的相邻字段例如查询同级的另一个字段。IQueryProps在 types.ts 中定义为{ pattern: FormPathPattern; base: FormPathPattern; form: Form }。构造时的匹配逻辑Query构造函数会先把pattern与base合并解析为绝对路径this.pattern FormPath.parse(props.pattern, props.base)随后分两条路径收集匹配地址addresses: string[]精确模式非匹配模式如果pattern不是模糊匹配模式!this.pattern.isMatchPattern则直接通过takeMatchPattern在form.fields与form.indexes中查找标识符对应的绝对地址命中则addresses [matched]。这里优先查找绝对字段其次查找索引字段。匹配模式通配/正则遍历form.fields对每个字段调用field.match(this.pattern)判断是否命中命中则把地址压入addresses。因此 Query 的结果集在构造时就已经确定后续所有方法都围绕这份addresses列表工作。一个通用的内部辅助函数Query.ts顶部的output函数决定了结果的形式const output (field, taker) { if (!field) return if (isFn(taker)) { return taker(field, field.address) } return field }不传回调时返回字段节点本身传回调时以(field, address)为参数调用回调并返回其结果字段不存在已被销毁时返回undefined。这正是take/map/forEach/reduce支持可选映射器的实现基础。三、遍历类方法take / map / forEach / reduce文档明确指出使用这四类方法时结果集中必须存在对应节点否则相关字段会得到undefined遍历将无内容可处理。3.1 take —— 提取结果集第一个节点描述从查询结果集中提取第一条结果可选传入getter对取到的字段做映射。文档强调读取前必须确认存在对应节点。签名Query.mdinterface take { (): GeneralField Result(getter: (field: GeneralField, address: FormPath) Result): Result }实现Query.tstake(taker?: any): any { return output(this.form.fields[this.addresses[0]], taker) }即取addresses[0]对应的字段再交给output处理。典型用法const field form.query(username).take() // 直接拿字段 const title form.query(username).take(f f.title) // 拿映射结果3.2 map —— 遍历并映射整个结果集描述对查询结果集逐一遍历并映射返回与结果集等长的新数组。签名interface map { (): GeneralField[] Result(mapper?: (field: GeneralField, address: FormPath) Result): Result[] }实现map(iterator?: any): any { return this.addresses.map((address) output(this.form.fields[address], iterator) ) }不传mapper时返回字段节点数组GeneralField[]传入mapper时返回映射后的Result[]。mapper接收两个参数字段节点field与路径对象addressFormPath实例。// 收集所有以 user 开头的字段的标题 const titles form.query(user.*).map((f) f.title) // 直接获取所有匹配字段节点 const fields form.query(*).map()3.3 forEach —— 仅遍历不返回描述遍历查询结果集与map的区别是不产生返回值。签名interface forEach { Result(eacher: (field: GeneralField, address: FormPath) Result): void }实现forEachResult(iterator) { return this.addresses.forEach((address) output(this.form.fields[address], iterator) ) }Form 内部大量使用forEach批量操作字段例如clearErrorsForm.tsclearErrors (pattern: FormPathPattern *) { this.query(pattern).forEach((field) { if (!isVoidField(field)) { field.setFeedback({ type: error, messages: [] }) } }) }类似地clearWarnings、clearSuccesses、onUnmount中的字段销毁this.query(*).forEach((field) field.destroy(false))、clearFormGraph等都依赖forEach完成批量遍历。3.4 reduce —— 结果集归约描述对查询结果集执行归约reduce操作可传入初始值。签名interface reduce { Result( reducer: (value: Result, field: GeneralField, address: FormPath) Result, initial?: Result ): Result }实现Query.tsreduceResult(reducer, initial?: Result): Result { return this.addresses.reduce( (value, address) output(this.form.fields[address], (field, address) reducer(value, field, address) ), initial ) }reducer每次回调收到三个参数累计值value、当前字段field、当前路径address。Form 的queryFeedbacksForm.ts就是 reduce 的经典用例——把多个字段的反馈消息汇聚成一条数组queryFeedbacks (search: ISearchFeedback): IFormFeedback[] { return this.query(search.address || search.path || *).reduce( (messages, field) { if (isVoidField(field)) return messages return messages.concat( field .queryFeedbacks(search) .map((feedback) ({ ...feedback, address: field.address.toString(), path: field.path.toString(), })) .filter((feedback) feedback.messages.length 0) ) }, [] ) }四、读取类方法get / getIn / value / initialValue这组方法用于取出第一个匹配节点的某个状态属性无需自己调用take再取属性。4.1 get —— 读取第一个节点的指定属性描述从查询结果集中找到第一个结果并读取它的指定属性。K被约束为IGeneralFieldState的键因此具有类型安全。文档同样强调读取前必须确认节点存在。签名interface get { K extends keyof IGeneralFieldState(key: K): IGeneralFieldState[K] }IGeneralFieldState IFieldState IVoidFieldState见 types.ts涵盖value、initialValue、display、pattern、title、description、required、disabled、visible、editable等通用字段状态。实现Query.tsgetK extends keyof IGeneralFieldState(key: K): IGeneralFieldState[K] { const results: any this.take() if (results) { return results[key] } }内部直接复用take()取第一个节点再读取键值。例如const required form.query(username).get(required) const visible form.query(password).get(visible)4.2 getIn —— 支持 FormPathPattern 的深度读取描述找到第一个结果后使用FormPathPattern路径语法在其状态内继续深度读取属性能力比get更强。签名interface getIn { (pattern?: FormPathPattern): any }实现getIn(pattern?: FormPathPattern) { return FormPath.getIn(this.take(), pattern) }它委托给FormPath.getIn因此可以穿透多层结构读取例如读取字段component的props中的某个深层选项const placeholder form.query(username).getIn(component.props.placeholder) const componentType form.query(username).getIn(component.type)FormPathPattern的完整语法参见 FormPath 文档文档中标注为/api/entry/form-path#formpathpattern对应页面。4.3 value —— 查询指定路径的值描述查询指定路径的当前值不限于 Field 节点——即对于任意路径即使没有对应字段节点也能读取表单数据中该路径的值。签名interface value { (): any }实现Query.tsvalue() { return this.get(value) }const v form.query(user.name).value()4.4 initialValue —— 查询指定路径的初始值描述查询指定路径的初始值同样不限于 Field 节点。签名interface initialValue { (): any }实现initialValue() { return this.get(initialValue) }const iv form.query(user.name).initialValue()五、匹配模式与相对路径Query 的进阶用法5.1 通配与模糊匹配当pattern是匹配模式isMatchPattern为真时Query 会对全量字段做field.match(this.pattern)过滤因此支持 Formily 路径语法中的通配符能力例如form.query(*.name) // 所有层级下的 name 字段 form.query(array.*.value) // 数组内每个元素的 value 字段 form.query(*) // 全部字段Form 中默认参数pattern: *的方法clearErrors、clearWarnings、clearSuccesses、clearFormGraph等都利用了这一特性实现对全表单字段的批量操作。5.2 相对路径与 buildDataPath从Field.query发起查询时base为当前字段地址此时this.pattern.haveRelativePattern为真构造函数会调用buildDataPath(form.fields, pattern)internals.ts把相对路径换算成基于数据的绝对路径再交给takeMatchPattern精确解析。这意味着你可以在一个字段的reactions或副作用逻辑中基于自身位置去找邻居field.query(.confirmPassword) // 以当前字段为基准的同级字段 field.query(..*) // 向上一级再匹配所有字段5.3 与 setFieldState / getFieldState 的分工Form 上还有setFieldState/getFieldStateForm.ts它们本质是按模式批量读写字段状态的更高层封装而 Query 是这一能力的基础设施。当需要更细粒度的遍历map/reduce/forEach、或需要拿到字段节点本身做进一步方法调用时直接使用form.query(pattern)更合适。六、源码结构总览Query 相关文件索引文件说明Query.mdQuery 对象 API 官方文档本文主体Query.tsQuery 类完整实现构造匹配、八个方法Form.tsForm.query入口及内部消费clearErrors 等BaseField.tsField.query入口相对路径基准types.tsIGeneralFieldState、GeneralField、IQueryProps类型定义internals.tsbuildDataPath相对路径换算实现models/index.tsQuery 等模型的统一导出入口七、小结何时用哪个方法只需第一个匹配字段或其属性 →take()/take(getter)需要批量收集匹配字段或派生数据 →map()/map(mapper)需要批量副作用清空错误、销毁字段、设置状态→forEach()需要汇总聚合多个字段的数据如汇总反馈消息→reduce(reducer, initial?)读取第一个字段的指定状态键→get(key)类型安全读取第一个字段的深层嵌套属性→getIn(pattern?)支持 FormPathPattern读取任意路径的当前值 / 初始值不要求存在字段节点→value()/initialValue()。掌握 Query 的八种方法及其底层匹配机制你就能像 Formily 内部实现一样用一行form.query(pattern)精确、批量地操控任意表单字段状态写出更简洁且可维护的表单逻辑。【免费下载链接】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创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

基于 Phoenix 构建 AI/LLM 应用评估器:从错误分析到 CI 门禁的完整实战指南
基于 Phoenix 构建 AI/LLM 应用评估器:从错误分析到 CI 门禁的完整实战指南

可观测性AI 评测LLMOpsAI 应用人工智能 【免费下载链接】phoenix AI Observability & Evaluation 项目地址: https://gitcode.com/gh_mirrors/phoenix13/phoenix 点击查看 免费下载 Phoenix 的 evals 技能文档(.agents/skills/phoenix-evals/SKILL.… · 2026/9/23 14:26:23

Robot Framework 任务执行完全指南:RPA 通用自动化模式与 --rpa/--norpa/--task 实战解析
Robot Framework 任务执行完全指南:RPA 通用自动化模式与 --rpa/--norpa/--task 实战解析

测试RPA接口测试 【免费下载链接】robotframework Generic automation framework for acceptance testing and RPA 项目地址: https://gitcode.com/gh_mirrors/ro/robotframework 点击查看 免费下载 本文聚焦 Robot Framework 的**任务执行(Task Execut… · 2026/9/23 14:26:23

一文搞懂幽灵废墟的宝藏在哪:3个致命报错的避坑实录
一文搞懂幽灵废墟的宝藏在哪:3个致命报错的避坑实录

一文搞懂幽灵废墟的宝藏在哪:3个致命报错的避坑实录 面对满屏红色的 StackTrace,是不是感觉脑子像被塞了一团乱麻?报错信息长得像天书,复制出来搜半天也没个准信。别慌,今天我们就用大白话,把那些藏在“幽灵废墟”里的技术宝藏挖出来,一文… · 2026/9/23 14:26:23

2026徐州公司注册代办机构评测:五家正规服务与合规创业指南
2026徐州公司注册代办机构评测:五家正规服务与合规创业指南

行业背景徐州是淮海经济区中心城市,综合交通与商贸优势突出,营商环境持续优化,市场主体规模稳步扩大。截至2025年底,全市市场经营主体总量达151.85万户,其中企业39.67万户、个体工商户111.61万户,市场主体梯… · 2026/9/23 15:11:18

面试官问收数据超时?3个性能优化坑让你直接凉
面试官问收数据超时?3个性能优化坑让你直接凉

面试官问收数据超时?3个性能优化坑让你直接凉 刚毕业那会儿,我盯着官方文档里的“高并发数据接收”章节看了三小时,眼睛都花了,还是没搞懂为什么我的服务一上压测就崩。直到在GitHub 开源仓库里翻到几个真实的生产事故复盘,我才明白:… · 2026/9/23 15:11:12

PCA+KMeans 双时相变化检测:无训练样本的遥感影像快速变化识别
PCA+KMeans 双时相变化检测:无训练样本的遥感影像快速变化识别

简介:这是一份基于主成分分析与K-means聚类的遥感图像变化检测实战资源,面向遥感地物识别、环境监测等方向的学习者与研究者,解决多时相影像中地表变化区域的自动提取问题。压缩包共14个文件,以4个Python脚本为核心,覆… · 2026/9/23 15:11:11

YOLOv5测试数据集实战:用COCO预训练权重检测人、猫、狗
YOLOv5测试数据集实战:用COCO预训练权重检测人、猫、狗

简介:这是一份用于YOLOv5模型评估的测试数据集,图像中主要包含人、猫、狗三类目标,适合目标检测初学者验证训练效果,也可用于测试自训练权重或做迁移学习实验。资源包共501个文件,包括200张jpg原图、100个xml标注文件以… · 2026/9/23 15:11:11

30 Seconds of Interviews:用 Array.reduce 生成斐波那契数列数组的 JavaScript 实现与面试拆解
30 Seconds of Interviews:用 Array.reduce 生成斐波那契数列数组的 JavaScript 实现与面试拆解

30 Seconds of Interviews:用 Array.reduce 生成斐波那契数列数组的 JavaScript 实现与面试拆解 【免费下载链接】30-seconds-of-interviews A curated collection of common interview questions to help you prepare for your next interview. 项目地址: https:… · 2026/9/23 15:11:11

离散系数详解:如何正确比较不同变量的离散程度
离散系数详解:如何正确比较不同变量的离散程度

做数据分析,再怎么绕都绕不开一个词:离散程度。两个数据集,均值算出来差不多,但一个在平均线周围紧贴着,一个散得满世界乱跑,如果只看平均值,你很容易被坑。可另一句实话是:直接看标… · 2026/9/23 15:11:03

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

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

企业微信二维码