Files
workspace/code/fms/.qoder/repowiki/zh/content/表格系统/表格系统.md
T
2026-08-23 21:02:41 +08:00

19 KiB
Raw Blame History

表格系统

**本文引用的文件** - [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)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本技术文档聚焦 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 主组件
    • 虚拟滚动:基于阈值动态启用/关闭虚拟滚动,避免小数据量下的“吞掉最后一行”问题;支持 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 作为门面组件,聚合以下职责:

  • 将用户传入的 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 主组件

  • 虚拟滚动策略
    • 当数据行数超过阈值(默认 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 : "使用"

图表来源

章节来源

分页组件与表格集成

  • 分页组件特性
    • 受控与非受控模式,页码边界收敛,页码窗口折叠(当前页前后各 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 行数保持可视区范围、非编辑态零编辑器组件、进入编辑后仅活动行挂载编辑器等场景。

章节来源

故障排查指南

  • 虚拟滚动异常
    • 现象:小数据量下最后一行不可见或滚动异常。
    • 排查:检查 effectiveVirtual 阈值与 dataSource.length;确认容器尺寸有效(width/height > 0)。
    • 参考:FmsTable.vue:41-68、FmsTable.vue:82-96
  • 编辑态丢失或闪烁
  • 选择列状态异常
    • 现象:全选/半选状态不正确或禁用行未生效。
    • 排查:检查 getSelectedRowKeys、isRowDisabled 回调;确认 rowByKey 映射正确。
    • 参考:createSelectionCellRenderers.js:26-56
  • 分页与表格数据不同步
    • 现象:切换页码后表格数据未更新。
    • 排查:确认 Pagination 的 change 事件已更新 dataSource;检查虚拟滚动是否需要重新初始化。
    • 参考:Pagination.vue:93-126、FmsTable.vue:41-68

章节来源

结论

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 组件。

章节来源