19 KiB
19 KiB
表格系统
**本文引用的文件** - [FmsTable.vue](file://fms-vue/src/components/fms-table/FmsTable.vue) - [createCellRenderer.js](file://fms-vue/src/components/fms-table/utils/createCellRenderer.js) - [createEditableCellRenderer.js](file://fms-vue/src/components/fms-table/utils/createEditableCellRenderer.js) - [createSelectionCellRenderers.js](file://fms-vue/src/components/fms-table/utils/createSelectionCellRenderers.js) - [Pagination.vue](file://fms-vue/src/components/ui/pagination/Pagination.vue) - [fms-table-virtual.spec.js](file://fms-vue/tests/fms-table-virtual.spec.js)目录
简介
本技术文档聚焦 FMS 高性能表格系统,围绕 FmsTable 组件深入解析其虚拟滚动、大数据量渲染优化与内存管理机制;详细说明列定义、行内编辑、排序筛选、分页等配置能力;阐述单元格渲染器扩展机制(自定义组件与复杂数据类型);总结增量更新、懒加载与缓存策略;并提供在业务场景中的使用模式与最佳实践(与表单、弹窗等集成)。
项目结构
FmsTable 位于 fms-vue 的组件目录中,核心由主组件与三个工具模块构成:
- 主组件:负责虚拟滚动开关、尺寸监听与刷新、编辑态管理、选择列注入、事件转发与对外方法暴露。
- 工具模块:
- createCellRenderer.js:根据列配置生成 actions 列渲染器,并决定何时注入编辑器渲染。
- createEditableCellRenderer.js:实现输入框、下拉、复选框等行内编辑器的创建、焦点控制、草稿提交与变更通知。
- createSelectionCellRenderers.js:提供选择列(含全选/半选状态)与判断是否为选择列的工具。
- 分页组件:独立的 Pagination.vue,可与表格组合实现前端分页或配合后端分页。
graph TB
A["FmsTable.vue"] --> B["createCellRenderer.js"]
A --> C["createEditableCellRenderer.js"]
A --> D["createSelectionCellRenderers.js"]
A --> E["Pagination.vue"]
图表来源
- FmsTable.vue:1-828
- createCellRenderer.js:1-229
- createEditableCellRenderer.js:1-212
- createSelectionCellRenderers.js:1-135
- Pagination.vue:1-235
章节来源
核心组件
- FmsTable 主组件
- 虚拟滚动:基于阈值动态启用/关闭虚拟滚动,避免小数据量下的“吞掉最后一行”问题;支持 X/Y 方向虚拟滚动。
- 尺寸自适应:ResizeObserver + requestAnimationFrame 合并多次尺寸变化,仅宽度变化时只重算 X 方向,减少重排。
- 行内编辑:WeakMap 存储每行编辑态,editingActive 控制是否注入编辑器渲染,避免滚动时每格函数式组件重渲染。
- 选择列:通过 createSelectionColumn 注入首列,封装选中集合计算与全选/半选逻辑。
- 动作列:actions 列支持按钮、更多菜单、确认弹窗等,统一渲染与事件处理。
- 对外 API:scrollToRow、editRow、getSelectedArea、clearSelectedArea、setRowExpand、initVirtualScroll 等。
- 单元格渲染器
- resolveCustomCell:按列配置决定是否注入 customCell;非编辑态的可编辑列走原生 td 路径,减少组件开销。
- 可编辑单元格:Input/Select/Checkbox 三种内置编辑器,支持焦点控制、草稿暂存、失焦提交、键盘交互。
- 选择列渲染:原生 checkbox + CSS 模拟 antdv-next 外观,零组件开销。
- 分页组件
- 受控/非受控两种模式,支持页码窗口折叠、快速跳转、每页条数切换、总数展示等。
章节来源
- FmsTable.vue:10-554
- createCellRenderer.js:208-229
- createEditableCellRenderer.js:1-212
- createSelectionCellRenderers.js:18-135
- Pagination.vue:8-126
架构总览
FmsTable 作为门面组件,聚合以下职责:
- 将用户传入的 columns 转换为 displayColumns,按需注入序号列、拖拽列、选择列,并为可编辑列注入编辑器渲染。
- 通过 StkTable 实现底层虚拟滚动与区域选择,FmsTable 在其之上增强编辑体验与性能。
- 通过 WeakMap 与 shallowRef 维护行级编辑态,结合 editingActive 标志控制渲染路径。
- 通过 ResizeObserver 与 rAF 合并尺寸变化,最小化重排。
- 对外暴露方法供父组件调用,如新增后滚动到行并进入编辑。
sequenceDiagram
participant Parent as "父组件"
participant Table as "FmsTable.vue"
participant Utils as "createCellRenderer.js"
participant Edit as "createEditableCellRenderer.js"
participant Sel as "createSelectionCellRenderers.js"
participant UI as "Pagination.vue"
Parent->>Table : 传入 columns/dataSource/rowSelection
Table->>Utils : resolveCustomCell(列配置, 编辑上下文)
Utils-->>Table : 返回带 customCell 的列定义
Table->>Sel : createSelectionColumn(...)
Sel-->>Table : 返回选择列对象
Table->>UI : 可选组合分页前端分页或联动后端
Note over Table,UI : 表格渲染与分页解耦,可按需组合
图表来源
- FmsTable.vue:273-334
- createCellRenderer.js:208-229
- createSelectionCellRenderers.js:18-135
- Pagination.vue:8-126
详细组件分析
FmsTable 主组件
- 虚拟滚动策略
- 当数据行数超过阈值(默认 100)时启用虚拟滚动,否则全量渲染,避免小数据量下最后几行不可见的问题。
- 支持 virtualX 单独开启横向虚拟滚动。
- 尺寸监听与刷新
- 使用 ResizeObserver 监听容器尺寸变化,rAF 合并多次通知,仅在稳定后触发 initVirtualScroll。
- 若仅宽度变化,调用 initVirtualScrollX 仅重算 X 方向,降低开销。
- 行内编辑与焦点管理
- 使用 WeakMap 存储每行的编辑态(editing、focusCol、initialValues),shallowRef 保证局部响应式。
- editingActive 为 true 时才为可编辑列注入 customCell,否则走原生 td 渲染,减少滚动时的函数式组件重建。
- 键盘导航期间(按住方向键)延迟激活编辑器,避免频繁挂载/卸载导致掉帧。
- 选择列
- 通过 createSelectionColumn 注入首列,封装 selectedRowKeySet 计算与全选/半选逻辑,支持禁用行。
- 动作列
- 支持 inline 按钮与 more 下拉菜单,支持 confirm 确认弹窗(danger 类型默认),事件冒泡隔离。
- 对外方法
- scrollToRow、editRow、getSelectedArea、clearSelectedArea、setRowExpand、initVirtualScroll、refreshLayout。
flowchart TD
Start(["进入渲染"]) --> CheckData["检查数据行数"]
CheckData --> |> 阈值| EnableVirt["启用虚拟滚动"]
CheckData --> |<= 阈值| FullRender["全量渲染"]
EnableVirt --> Render["渲染可见区"]
FullRender --> Render
Render --> Resize{"尺寸变化?"}
Resize --> |是| Debounce["防抖合并(rAF)"]
Debounce --> Refresh["initVirtualScroll / initVirtualScrollX"]
Resize --> |否| End(["结束"])
Refresh --> End
图表来源
章节来源
单元格渲染器扩展机制
- resolveCustomCell
- 若列已定义 customCell,直接返回。
- 若列有 editor 且处于活动编辑态,或为 checkbox/select 类型,则注入 createEditableCell。
- 若列有 actions,则注入 createActionsCell。
- 其他情况不注入 customCell,走库原生 td 渲染路径,提升滚动性能。
- 可编辑单元格
- Input:支持 text/password/number/textarea,失焦提交,Enter 全选,Escape 取消。
- Select:支持 options 函数或数组,空值处理,即时提交。
- Checkbox:始终可交互,点击即切换,键盘 Enter 支持切换。
- 焦点控制:onVnodeMounted/Updated 确保聚焦与选择行为;focus 选项支持 preventScroll。
- 草稿机制:WeakMap 暂存输入草稿,卸载前兜底写回,避免整表更新。
- 选择列渲染
- 原生 input[type=checkbox] + CSS 样式模拟,零组件开销,避免每行创建组件实例导致的性能退化。
classDiagram
class CreateCellRenderer {
+resolveCustomCell(col, ctx, editingActive)
}
class EditableCellRenderer {
+createEditableCell(col, ctx)
-createInput(row, col, editor, ctx)
-createSelect(row, col, editor, ctx)
-createCheckbox(row, col, editor, ctx)
}
class SelectionCellRenderers {
+createSelectionColumn(options)
+isSelectionColumn(col)
}
CreateCellRenderer --> EditableCellRenderer : "调用"
CreateCellRenderer --> SelectionCellRenderers : "使用"
图表来源
- createCellRenderer.js:208-229
- createEditableCellRenderer.js:1-212
- createSelectionCellRenderers.js:18-135
章节来源
- createCellRenderer.js:1-229
- createEditableCellRenderer.js:1-212
- createSelectionCellRenderers.js:1-135
分页组件与表格集成
- 分页组件特性
- 受控与非受控模式,页码边界收敛,页码窗口折叠(当前页前后各 1 页,省略号跳 ±5 页)。
- 支持每页条数切换、快速跳转、总数展示插槽。
- 与表格集成建议
- 前端分页:将 dataSource 切片后传给表格,结合 Pagination 的 change/showSizeChange 事件刷新数据。
- 后端分页:表格仅显示当前页数据,分页组件驱动查询参数(page/pageSize),适合超大数据集。
sequenceDiagram
participant User as "用户"
participant Page as "Pagination.vue"
participant Table as "FmsTable.vue"
User->>Page : 切换页码/每页条数
Page-->>User : emit change(current, pageSize)
User->>Table : 更新 dataSource分页后的数据
Table->>Table : 重新计算虚拟滚动/渲染
图表来源
章节来源
依赖关系分析
- 组件耦合
- FmsTable 强依赖 stk-table-vue 提供的虚拟滚动与区域选择能力,并通过 props 与事件与之协作。
- 工具模块低耦合:createCellRenderer 依赖可编辑渲染器与选择列渲染器,便于独立测试与复用。
- 外部依赖
- Vue 响应式:ref、computed、watch、nextTick、useSlots 等。
- 主题与 UI:通过 appStore 获取深色模式,使用内部 UI 组件(Button、Modal、Dropdown、Input、Select)。
- 潜在循环依赖
- 当前结构无循环依赖,工具模块仅被主组件引用。
graph LR
F["FmsTable.vue"] --> R1["createCellRenderer.js"]
F --> R2["createEditableCellRenderer.js"]
F --> R3["createSelectionCellRenderers.js"]
R2 --> U1["Input.vue"]
R2 --> U2["Select.vue"]
R1 --> U3["Modal.vue"]
R1 --> U4["Dropdown.vue"]
R1 --> U5["Button.vue"]
图表来源
章节来源
性能考量
- 虚拟滚动与阈值控制
- 数据行数小于阈值时关闭虚拟滚动,避免小数据集出现“吞掉最后一行”的问题;超过阈值启用虚拟滚动,仅渲染可视区。
- 渲染路径优化
- 非编辑态的可编辑列与纯展示列走原生 td 渲染,不注入 customCell,减少函数式组件数量。
- 仅活动编辑行挂载编辑器,其余行保持原生渲染,避免滚动时整表重建。
- 尺寸变化合并
- ResizeObserver + rAF 合并多次尺寸变化,仅宽度变化时只重算 X 方向,减少重排与重绘。
- 编辑态管理
- WeakMap 存储行级编辑态,shallowRef 降低响应式开销;草稿机制避免频繁提交与整表更新。
- 键盘导航优化
- 长按方向键期间延迟激活编辑器,松开后再恢复最终目标行,避免每帧创建/销毁组件导致卡顿。
- 测试验证
- 单元测试覆盖 5000 行虚拟滚动生效、20 行全量渲染、数据增长后 DOM 行数保持可视区范围、非编辑态零编辑器组件、进入编辑后仅活动行挂载编辑器等场景。
章节来源
- FmsTable.vue:41-96
- createCellRenderer.js:208-229
- createEditableCellRenderer.js:17-49
- fms-table-virtual.spec.js:30-153
故障排查指南
- 虚拟滚动异常
- 现象:小数据量下最后一行不可见或滚动异常。
- 排查:检查 effectiveVirtual 阈值与 dataSource.length;确认容器尺寸有效(width/height > 0)。
- 参考:FmsTable.vue:41-68、FmsTable.vue:82-96
- 编辑态丢失或闪烁
- 现象:切换行编辑时闪烁或编辑内容丢失。
- 排查:确认 WeakMap 行级状态正确绑定;草稿机制在卸载前写回;editingActive 控制渲染路径。
- 参考:FmsTable.vue:99-174、createEditableCellRenderer.js:17-49
- 选择列状态异常
- 现象:全选/半选状态不正确或禁用行未生效。
- 排查:检查 getSelectedRowKeys、isRowDisabled 回调;确认 rowByKey 映射正确。
- 参考:createSelectionCellRenderers.js:26-56
- 分页与表格数据不同步
- 现象:切换页码后表格数据未更新。
- 排查:确认 Pagination 的 change 事件已更新 dataSource;检查虚拟滚动是否需要重新初始化。
- 参考:Pagination.vue:93-126、FmsTable.vue:41-68
章节来源
- FmsTable.vue:41-174
- createSelectionCellRenderers.js:26-56
- createEditableCellRenderer.js:17-49
- Pagination.vue:93-126
结论
FmsTable 通过虚拟滚动、渲染路径优化、编辑态管理与尺寸变化合并等策略,实现了在大中型数据集下的高性能表格体验。其可扩展的单元格渲染器机制支持丰富的业务需求,并与分页组件解耦,便于在不同场景下灵活组合。建议在业务中使用前端分页处理中小数据集,后端分页处理超大数据集;同时充分利用编辑态懒挂载与草稿机制,确保流畅的用户交互。
附录
- 配置选项速览(基于源码导出)
- 虚拟滚动:virtual、virtualX、effectiveVirtual(阈值控制)
- 列相关:columns、seq、columnDraggable、editable、showOverflow、noDataFull
- 行相关:dataSource、rowKey、activeRowKey、rowDraggable、rowSelection
- 主题:theme(light/dark,默认跟随应用)
- 对外方法:scrollToRow、editRow、getSelectedArea、clearSelectedArea、setRowExpand、initVirtualScroll、refreshLayout
- 使用模式建议
- 与表单集成:在弹窗或抽屉中嵌入 FmsTable,新增行后调用 editRow 进入编辑;保存时收集 change 事件产生的差异。
- 与弹窗集成:actions 列支持 confirm 确认弹窗,危险操作默认 danger 类型,统一交互体验。
- 分页策略:大数据集采用后端分页,小数据集可采用前端分页并结合 Pagination 组件。
章节来源