BaseTable 架构设计
目录
组件概述
BaseTable 是基于 Arco Design 的 Table 组件封装的高级数据表格组件,提供了丰富的功能特性和灵活 的扩展能力。该组件采用模块化设计,通过组合式 API 和 Hook 系统实现了功能的解耦与复用。
核心特性
- 数据绑定: 支持双向绑定数据源,自动同步数据变化
- 列配置: 灵活的列定义,支持自定义渲染、插槽、样式等
- 分页功能: 内置分页控件,支持远程数据加载
- 行选择: 支持单选/多选,提供选择状态管理
- 虚拟滚动: 大数据量场景下的性能优化
- 拖拽排序: 支持行拖拽调整顺序
- 自动高度: 自适应容器高度
- 国际化: 完整的多语言支持
- 自定义渲染: 支持 Render 函数和插槽两种方式
架构设计
BaseTable 采用分层架构设计,将功能划分为多个独立的模块,通过依赖注入和组合式 API 实现模块间的协作。
模块职责
| 模块 | 文件 | 职责 |
|---|---|---|
| 主组件 | BaseTable.tsx | 组件入口,组合各模块功能 |
| 属性定义 | Props.ts | 定义组件属性和事件 |
| 类型定义 | BaseTable.d.ts | TypeScript 类型声明 |
| 状态管理 | useState.ts | 组件状态初始化和共享 |
| 事件处理 | useEvent.ts | 用户交互事件处理 |
| 生命周期 | useHook.ts | 组件Hook和业务逻辑 |
| 列渲染 | useColumns.tsx | 列定义和插槽处理 |
| 工具函数 | useUtils.ts | 通用工具和国际化 |
| API接口 | api.ts | 数据请求和排序接口 |
| 自动提示 | AutoTooltip.tsx | 文本溢出提示组件 |
| 事件定义 | events.ts | 自定义事件列表 |
核心模块
1. Props 属性系统 (Props.ts)
Props 模块定义了组件的所有输入属性和事件,采用 Vue 3 的 PropType 进行类型约束。
核心属性分类:
// 数据相关
- columns: 列配置数组
- dataSource: 数据源
- url: 远程数据地址
- dataTransformer: 数据转换函数
// 显示控制
- isSeq: 是否显示序号
- isHidePagination: 是否隐藏分页
- isVScroll: 是否启用虚拟滚动
- autoHeight: 是否自动高度
// 交互功能
- isChecked: 是否支持选择
- isDrag: 是否支持拖拽
- radio: 是否单选模式
- columnResizable: 列宽可调整
// 样式定制
- cellStyle: 单元格样式
- rowStyle: 行样式
- rowClassName: 行类名
- hightLightRow: 高亮行颜色
// 国际化
- LanguageScopeKey: 语言作用域
2. 状态管理 (useState.ts)
状态管理模块使用 Vue 3 的 provide/inject 机制实现状态共享,确保所有子模块都能访问全局状态。
状态结构:
依赖注入模式:
// 创建状态
export const createState = (props, ctx) => {
const store = useStore(props, ctx)
provide(KEY, store) // 注入到子组件
return store
}
// 使用状态
export const injectState = () => {
return inject(KEY) as StoreType
}
3. 事件处理 (useEvent.ts)
事件模块负责处理用户交互,包括行点击、列调整、行选择等操作。
事件处理流程:
核心事件:
| 事件名 | 触发时机 | 参数 |
|---|---|---|
| onRowClick | 行点击 | record: TableData |
| onColumnResize | 列宽调整 | dataIndex: string, width: number |
| onSelect | 单行选择 | selectedRowKeys, selectedRows |
| onSelectAll | 全选/反选 | isCheck: boolean |
4. 生命周期 Hook (useHook.ts)
Hook 模块管理组件的生命周期逻辑和业务功能。
核心功能:
- 自动高度计算: 使用 ResizeObserver 监听容器大小变化
- 数据加载: 远程数据获取和本地数据更新
- 行高亮: 当前行的视觉反馈
- 分页处理: 分页参数管理
// 自动高度计算
onMounted(() => {
const resizeObserver = new ResizeObserver(debounce((entries) => {
const height = entries[0].borderBoxSize[0].blockSize
currentHeight.value = height
}, 150))
resizeObserver.observe(baseTableRef.value)
})
// 数据加载
const getList = async (query = {}) => {
const params = { ...baseParams.value, ...query }
const res = await getListData(params, props.url)
dataSource.value = props.dataTransformer ?
props.dataTransformer(res.items) : res.items
totalCount.value = res.totalCount
}
5. 列渲染系统 (useColumns.tsx)
列渲染模块处理表格列的渲染逻辑,支持插槽和 Render 函数两种方式。
渲染优先级:
渲染逻辑:
const RenderSlot = ({ column, record, rowIndex }) => {
const cellStyle = getCellStyle({ column, record, rowIndex })
// 优先级1: 插槽渲染
if (ctx.slots[column.field]) {
return <div class={styles.bodyCell} style={cellStyle}>
{ctx.slots[column.field]({ column, record, rowIndex })}
</div>
}
// 优先级2: Render函数
const render = column.customRender ||
(() => <AutoTooltip text={getValue(record, column.field)} />)
return <div class={styles.bodyCell} style={cellStyle}>
{render({ column, record, rowIndex })}
</div>
}
数据流设计
BaseTable 的数据流采用单向数据流和双向绑定相结合的模式。
数据加载流程
- 初始化: Props 传入初始数据源
- 响应式绑定: 使用
useVModels实现双向绑定 - 远程加载: 通过
url属性配置自动加载 - 数据转换:
dataTransformer预处理数据 - 状态更新: 更新
dataSource和totalCount - 触发事件: 发射
reload事件通知父组件
性能优化的数据映射
// 使用 Map 提升查找性能
const dataSourceMap = computed(() => {
const map = new Map<string, any>()
for (const item of dataSource.value) {
map.set(item[rowId.value], item)
}
return map
})
// O(1) 时间复杂度获取记录
const getRecordsByKeys = (keys: string[]) => {
return keys.map(key => dataSourceMap.value.get(key)).filter(Boolean)
}
状态管理
状态分类
BaseTable 的状态可分为以下几类:
状态同步机制
// 1. 父子组件同步 - useVModels
const { dataSource } = useVModels(props, ctx.emit)
// 2. 跨模块同步 - provide/inject
provide(KEY, store)
const store = inject(KEY)
// 3. 选择状态同步
watch(selectedKeys, async () => {
await nextTick()
const records = getRecordsByKeys(selectedKeys.value)
emit('check', records)
})
Hook系统
BaseTable 的 Hook 系统负责处理组件的副作用和业务逻辑。
核心 Hook 功能
1. 自动高度 Hook
const autoHeight = computed(() => {
if (baseTableRef.value) {
const rect = baseTableRef.value.getBoundingClientRect()
const rectHeight = currentHeight.value || rect.height
return rectHeight > 42 ? rectHeight - 42 : rectHeight
}
})
工作原理:
- 使用
ResizeObserver监听容器尺寸变化 - 防抖处理避免频繁计算
- 减去表头高度 (42px) 得到内容区域高度
- 配合虚拟滚动使用