# Bricks.js 表单模块技术文档 > 本文档描述了 `bricks` 框架中表单相关组件的实现逻辑、结构与使用方式。该模块提供了灵活的表单构建能力,支持动态字段渲染、数据校验、提交处理及工具栏集成。 --- ## 目录 - [概述](#概述) - [核心变量](#核心变量) - [核心方法](#核心方法) - [类说明](#类说明) - [`FieldGroup`](#fieldgroup) - [`FormBody`](#formbody) - [`FormBase`](#formbase) - [`InlineForm`](#inlineform) - [`Form`](#form) - [工厂注册](#工厂注册) - [使用示例](#使用示例) --- ## 概述 本模块为 `bricks.js` 提供了一套完整的表单系统,包含以下功能: - 动态生成表单字段(支持嵌套分组) - 支持文件上传(需使用 `FormData`) - 自动化工具栏(提交、重置、取消按钮) - 数据获取与验证 - 提交前后事件分发 - 多布局支持(水平/垂直输入框) 主要适用于 Web 端复杂表单场景,如配置页、编辑器、数据录入等。 --- ## 核心变量 ### `bricks.need_formdata_fields` ```js bricks.need_formdata_fields = ['file', 'video', 'audio']; ``` **说明:** 指定哪些字段类型需要通过 `FormData` 提交(例如文件上传类字段)。这些字段将触发表单启用 `multipart/form-data` 编码模式。 --- ## 核心方法 ### `show_resp_message_or_error(resp)` ```js bricks.show_resp_message_or_error = async function(resp){...} ``` **参数:** - `resp`: `Response` 对象(来自 `fetch` 请求) **功能:** 1. 解析响应体为 JSON。 2. 调用 `widgetBuild` 将返回的 UI 描述渲染到页面主体中。 **用途:** 用于处理服务端返回的动态 UI 或错误信息并展示。 --- ## 类说明 ### `FieldGroup` 负责根据字段定义递归构建表单控件。 #### 构造函数 ```js new FieldGroup(opts) ``` - `opts`: 配置对象(目前未实际使用) #### 方法:`build_fields(form, parent, fields)` | 参数 | 类型 | 说明 | |----------|------------|------| | `form` | Form 实例 | 当前所属表单对象 | | `parent` | Widget | 容器组件(如 VBox/HBox) | | `fields` | Array | 字段数组 | **行为说明:** - 使用 `DynamicColumn` 实现响应式列布局(移动端默认两列)。 - 若遇到 `uitype: 'group'` 的字段,则递归构建其内部字段,并插入新列。 - 非隐藏字段创建 `VBox` 或 `HBox` 包裹标签和输入控件。 - 所有输入控件由 `Input.factory(field)` 创建,并存入 `form.name_inputs`。 - 若字段类型在 `need_formdata_fields` 中,设置 `form.need_formdata = true`。 --- ### `FormBody` 继承自 `VScrollPanel`,是表单内容区域的核心容器。 #### 构造函数 ```js new FormBody(form, opts) ``` **初始化操作:** - 设置宽高为 100% - 初始化 `name_inputs` 映射 - 创建 `FieldGroup` 渲染非文本字段 - 调用 `build_text_fields()` 渲染文本字段 #### 方法:`build_text_fields()` 遍历 `form.textfields`,对每个字段: - 创建标签文字 (`Text`) - 创建只读文本控件 (`UiText`) - 包装成 `VBox` 并添加至容器 - 注册到 `form.name_inputs` 中以便后续取值 > **注意:** `text` 类型字段不参与编辑,仅用于显示。 --- ### `FormBase` 表单基类,提供通用功能(继承自 `Layout`)。 #### 属性 | 属性名 | 类型 | 说明 | |-------------------|--------|------| | `name_inputs` | Object | 存储字段名 → 控件实例映射 | | `submit_changed` | Boolean| 是否仅提交变更字段 | | `origin_data` | Object | 初始数据快照(用于比对变化) | | `submit_url` | String | 提交地址 | | `method` | String | HTTP 方法,默认 `'POST'` | | `toolbar` | Object | 工具栏配置扩展 | #### 方法 ##### `build_toolbar(widget)` 动态构建顶部工具栏(含“提交”、“重置”、“取消”按钮),支持自定义扩展。 - 默认图标路径由 `bricks_resource()` 加载。 - 使用 `IconTextBar` 组件呈现按钮条。 - 绑定 `command` 事件到 `command_handle`。 ##### `command_handle(event)` 处理工具栏命令事件: | 命令名 | 行为 | |-----------|------| | `submit` | 触发 `validation()` | | `reset` | 调用 `reset_data()` | | `cancel` | 触发 `dispatch('cancel')` | | 其他 | 若有 `action` 则执行事件处理器;否则直接 `dispatch(name)` | ##### `reset_data()` 重置所有输入控件为其初始值(调用各控件的 `reset()` 方法)。 ##### `_getValue()` 收集所有字段值,进行必填校验: - 忽略无权访问的属性(`hasOwnProperty`) - 调用 `getValue()` 获取控件值 - 必填项为空时弹出错误提示并聚焦 - 返回合并后的数据对象 > ⚠️ 若校验失败则中断并返回 `undefined` ##### `getValue()` 优先返回缓存的 `this.data`,否则调用 `get_formdata()`。 ##### `get_formdata()` 构建 `FormData` 实例: - 遍历所有控件,调用 `set_formdata(data)` 写入数据 - 若启用了 `submit_changed`,跳过未修改字段 - 忽略值为 `null` 的字段 - 返回 `FormData` 或 `null`(无变更) ##### `validation()` 异步提交流程控制: 1. 显示加载动画(`Running` 组件) 2. 获取 `FormData` 3. 分发 `submit` 事件 4. 若设置了 `submit_url`,发起 HTTP 请求 5. 成功后分发 `submited` 事件,传入响应对象 6. 出错时捕获异常并输出日志 7. 隐藏加载动画 ##### `save_origin_data()` 保存当前所有字段值作为原始状态,用于后续变更判断。 --- ### `InlineForm` 轻量级内联表单,适合嵌入其他组件内部。 #### 特性: - 不包含标题或描述 - 直接渲染字段 + 工具栏 - 自动保存初始数据 #### 构造函数 ```js new InlineForm(opts) ``` **行为:** - 设置宽高 100%,开启滚动 - 调用 `FieldGroup.build_fields()` 渲染 `opts.fields` - 添加工具栏到第一个子容器 - 保存初始数据 --- ### `Form` 完整表单组件,具备标题、描述、分栏、工具栏等功能。 #### 配置选项(`opts`) | 参数 | 类型 | 说明 | |----------------|----------|------| | `title` | String | 表单标题(可国际化) | | `description` | String | 表单描述文本 | | `notoolbar` | Boolean | 是否隐藏工具栏,默认 `false` | | `input_layout` | String | 输入框布局 `"VBox"`(默认)或 `"HBox"` | | `fields` | Array | 字段定义数组 | | `submit_url` | String | 提交 URL | | `method` | String | HTTP 方法(GET/POST) | | `toolbar` | Object | 自定义工具栏配置 | #### 构造流程 1. 设置尺寸与滚动 2. 添加标题(若有) 3. 添加描述(若有) 4. 添加填充容器 `Filler` 5. 分离 `text` 与其他字段 6. 创建 `FormBody` 渲染主体内容 7. 条件性构建工具栏 8. 保存初始数据 --- ## 工厂注册 ```js bricks.Factory.register('InlineForm', bricks.InlineForm); bricks.Factory.register('Form', bricks.Form); ``` 允许通过字符串名称动态创建组件实例,便于模板化渲染。 --- ## 使用示例 ### 定义一个简单表单 ```js var form = new bricks.Form({ title: "User Profile", description: "Please fill in your information.", submit_url: "/api/user/update", method: "POST", input_layout: "VBox", fields: [ { name: "username", label: "Username", uitype: "text_input", required: true }, { name: "email", label: "Email", uitype: "email", required: true }, { name: "avatar", label: "Avatar", uitype: "file" }, { name: "bio", label: "Bio", uitype: "textarea" }, { uitype: "group", fields: [ { name: "phone", label: "Phone", uitype: "tel" }, { name: "age", label: "Age", uitype: "number" } ] } ] }); // 监听提交事件 form.bind('submit', function(data){ console.log("Submitting:", data); }); form.bind('submited', function(resp){ alert("Saved successfully!"); }); ``` ### 内联表单示例 ```js var inline = new bricks.InlineForm({ fields: [ { name: "name", label: "Name", uitype: "text_input" }, { name: "status", label: "Status", uitype: "select", options: [...] } ], toolbar: { tools: [ { icon: "...", name: "custom", label: "Custom Action", action: "doSomething" } ] } }); inline.bind('command:custom', function(){ ... }); ``` --- ## 附录:字段定义格式 ```json [ { "name": "field_name", "label": "Display Label", "uitype": "text_input|email|file|group|hide|...", "required": true, "value": "default_value", "removable": false, "icon": "optional_icon_path" } ] ``` 其中: - `group`: 可嵌套子字段 - `text`: 仅展示,不可编辑 - `hide`: 隐藏字段(但仍会渲染占位) --- ## 注意事项 - 文件上传字段必须使用 `FormData`,确保 `submit_url` 接口支持 `multipart/form-data`。 - 所有文本标签建议启用 `i18n: true` 实现多语言支持。 - 自定义控件需实现 `getValue()` 和 `set_formdata(formData)` 接口。 - 错误提示依赖 `bricks.Error` 组件,请确保已加载。 --- > 📚 更多组件参考请查阅 [Bricks.js 官方文档](https://github.com/your-bricks-project)。