跳到主要内容
版本:Next

BaseTable 架构设计

目录

  1. 组件概述
  2. 架构设计
  3. 核心模块
  4. 数据流设计
  5. 状态管理
  6. Hook系统
  7. 事件系统
  8. 渲染机制
  9. 性能优化
  10. 扩展性设计

组件概述

BaseTable 是基于 Arco Design 的 Table 组件封装的高级数据表格组件,提供了丰富的功能特性和灵活的扩展能力。该组件采用模块化设计,通过组合式 API 和 Hook 系统实现了功能的解耦与复用。

核心特性

  • 数据绑定: 支持双向绑定数据源,自动同步数据变化
  • 列配置: 灵活的列定义,支持自定义渲染、插槽、样式等
  • 分页功能: 内置分页控件,支持远程数据加载
  • 行选择: 支持单选/多选,提供选择状态管理
  • 虚拟滚动: 大数据量场景下的性能优化
  • 拖拽排序: 支持行拖拽调整顺序
  • 自动高度: 自适应容器高度
  • 国际化: 完整的多语言支持
  • 自定义渲染: 支持 Render 函数和插槽两种方式

架构设计

BaseTable 采用分层架构设计,将功能划分为多个独立的模块,通过依赖注入和组合式 API 实现模块间的协作。

模块职责

模块文件职责
主组件BaseTable.tsx组件入口,组合各模块功能
属性定义Props.ts定义组件属性和事件
类型定义BaseTable.d.tsTypeScript 类型声明
状态管理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 模块管理组件的生命周期逻辑和业务功能。

核心功能:

  1. 自动高度计算: 使用 ResizeObserver 监听容器大小变化
  2. 数据加载: 远程数据获取和本地数据更新
  3. 行高亮: 当前行的视觉反馈
  4. 分页处理: 分页参数管理
// 自动高度计算
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 的数据流采用单向数据流和双向绑定相结合的模式。

数据加载流程

  1. 初始化: Props 传入初始数据源
  2. 响应式绑定: 使用 useVModels 实现双向绑定
  3. 远程加载: 通过 url 属性配置自动加载
  4. 数据转换: dataTransformer 预处理数据
  5. 状态更新: 更新 dataSourcetotalCount
  6. 触发事件: 发射 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) 得到内容区域高度
  • 配合虚拟滚动使用

2. 数据加载 Hook

const getList = async (query = {}) => {
if (!props.url) return

const params = { ...baseParams.value, ...query }
const res = await getListData(params, props.url)

dataSource.value = props.dataTransformer ?
props.dataTransformer(res.items || res) :
res.items || res

totalCount.value = res.totalCount || res.length
ctx.emit('reload')

await nextTick()
return dataSource.value
}

3. 行高亮 Hook

const getRowClassName = (record: TableData, rowIndex: number) => {
if (record === currentRow.value) {
return styles.baseTableRow
}
}

const setCurrentRow = (key: string) => {
const row = dataSource.value.find(item => item[rowId.value] === key)
if (row) {
currentRow.value = row
}
}

事件系统

事件分类

BaseTable 支持两类事件:

  1. 标准事件 (来自 Arco Table)

    • select: 行选择
    • selectAll: 全选
    • rowClick: 行点击
    • columnResize: 列宽调整
  2. 自定义事件 (BaseTable 扩展)

    • update:dataSource: 数据源更新
    • load: 数据加载前
    • beforeLoad: 数据加载中
    • reload: 数据加载后
    • check: 选择状态变化

事件处理链

事件去抖处理

// 列宽调整使用防抖
const onColumnResize = debounce((dataIndex: string, width: number) => {
emit('columnResize', dataIndex, width)
}, 200)

渲染机制

渲染流程

插槽系统

BaseTable 提供了灵活的插槽系统:

const slotMap = {
// 序号列
seq: columnSeq.value.seq,

// 动态列插槽
...slots,

// 空数据插槽
empty: () => (
<div class={styles.nullData}>{_t('暂无数据')}</div>
)
}

使用示例:

<BaseTable :columns="columns" :dataSource="data">
<template #name="{ record }">
<a-link>{{ record.name }}</a-link>
</template>
</BaseTable>

AutoTooltip 组件

自动文本溢出提示组件,用于默认渲染场景。

工作原理:

  1. 挂载时检测文本是否溢出 (scrollWidth > clientWidth)
  2. 监听窗口 resize 事件重新检测
  3. 溢出时使用 Arco Tooltip 显示完整文本
  4. 未溢出时直接显示文本
const checkOverflow = () => {
if (containerRef.value) {
isOverflow.value =
containerRef.value.scrollWidth > containerRef.value.clientWidth
}
}

onMounted(() => {
checkOverflow()
window.addEventListener('resize', checkOverflow)
})

性能优化

1. 虚拟滚动

通过 isVScroll 开启虚拟滚动,只渲染可见区域的行。

virtual-list-props={
props.isVScroll ? { height: autoHeight.value } : undefined
}

适用场景: 数据量 > 1000 行

2. 数据映射优化

使用 Map 结构存储数据,提升查找效率:

// O(n) -> O(1)
const dataSourceMap = computed(() => {
const map = new Map()
for (const item of dataSource.value) {
map.set(item[rowId.value], item)
}
return map
})

3. 事件防抖

对高频事件进行防抖处理:

// 列宽调整
const onColumnResize = debounce((dataIndex, width) => {
emit('columnResize', dataIndex, width)
}, 200)

// 容器尺寸监听
const fn = debounce((entries) => {
currentHeight.value = entries[0].borderBoxSize[0].blockSize
}, 150)

4. 计算属性缓存

使用 computed 缓存计算结果:

const columns = computed(() => {
return props.columns.map(item => ({
...item,
title: _t(item.title)
}))
})

5. 条件渲染

根据配置按需渲染功能:

// 分页
pagination={props.isHidePagination ? false : {...}}

// 选择
row-selection={props.isChecked ? rowSelection : undefined}

// 拖拽
draggable={props.isDrag ? { type: 'handle', width: 20 } : undefined}

扩展性设计

1. 插件化架构

BaseTable 采用模块化设计,各功能模块独立可插拔:

// 核心模块
const { columns, dataSource, selectedKeys } = createState(props, ctx)
const events = useEvent(props, ctx)
const { getRowClassName, getTableStyle } = useHook(props, ctx)
const slots = ColumnSlots(props, ctx, columns)

2. Render 函数扩展

支持自定义渲染函数:

columns: [
{
field: 'status',
title: '状态',
customRender: ({ record }) => (
<a-tag color={record.status === 1 ? 'green' : 'red'}>
{record.status === 1 ? '启用' : '禁用'}
</a-tag>
)
}
]

3. 样式定制

多层次样式定制能力:

// 1. 行样式
rowStyle: (record) => ({ background: record.isNew ? '#f0f9ff' : '' })

// 2. 单元格样式
cellStyle: ({ record, column }) => ({
color: record.amount > 1000 ? 'red' : 'inherit'
})

// 3. 行类名
rowClassName: (record) => record.disabled ? 'disabled-row' : ''

// 4. 高亮行颜色
hightLightRow: '#e6f7ff'

4. 数据转换器

支持数据预处理:

<BaseTable
url="/api/users"
:dataTransformer="(data) => data.map(item => ({
...item,
fullName: `${item.firstName} ${item.lastName}`
}))"
/>

5. 国际化支持

完整的多语言支持:

// 自动翻译列标题
columns: [
{ field: 'name', title: '姓名' } // 自动翻译
]

// 支持作用域翻译
<BaseTable LanguageScopeKey="ProductManagement" />

6. 事件扩展

支持自定义事件监听:

// events.ts
export const events = [
'update:dataSource',
'load',
'beforeLoad',
'reload'
]

// 使用
<BaseTable
@reload="handleReload"
@check="handleCheck"
@select="handleSelect"
/>

最佳实践

1. 基础使用

<template>
<BaseTable
:columns="columns"
:dataSource="dataSource"
:isChecked="true"
@check="handleCheck"
/>
</template>

<script setup>
const columns = [
{ field: 'id', title: 'ID', width: 80 },
{ field: 'name', title: '姓名', width: 120 },
{ field: 'age', title: '年龄', width: 80 }
]

const dataSource = ref([
{ id: 1, name: '张三', age: 25 },
{ id: 2, name: '李四', age: 30 }
])

const handleCheck = (records) => {
console.log('选中的记录:', records)
}
</script>

2. 远程数据加载

<template>
<BaseTable
url="/api/users"
:columns="columns"
:pageSize="20"
:dataTransformer="transformData"
/>
</template>

<script setup>
const transformData = (data) => {
return data.map(item => ({
...item,
statusText: item.status === 1 ? '启用' : '禁用'
}))
}
</script>

3. 自定义渲染

<template>
<BaseTable :columns="columns" :dataSource="dataSource">
<template #status="{ record }">
<a-tag :color="record.status === 1 ? 'green' : 'red'">
{{ record.status === 1 ? '启用' : '禁用' }}
</a-tag>
</template>

<template #actions="{ record }">
<a-space>
<a-button size="mini" @click="handleEdit(record)">编辑</a-button>
<a-button size="mini" status="danger" @click="handleDelete(record)">
删除
</a-button>
</a-space>
</template>
</BaseTable>
</template>

4. 虚拟滚动 + 自动高度

<template>
<BaseTable
:columns="columns"
:dataSource="largeDataSource"
:isVScroll="true"
:autoHeight="true"
style="height: 500px"
/>
</template>

5. 拖拽排序

<template>
<BaseTable
:columns="columns"
:dataSource="dataSource"
:isDrag="true"
@change="handleDragSort"
/>
</template>

<script setup>
const handleDragSort = (data) => {
// 更新排序
console.log('新的排序:', data)
}
</script>

总结

BaseTable 是一个功能强大、高度可扩展的表格组件,具有以下特点:

设计优势

  1. 模块化架构: 功能解耦,易于维护和扩展
  2. 性能优化: 虚拟滚动、数据映射、事件防抖等多重优化
  3. 类型安全: 完整的 TypeScript 类型定义
  4. 灵活渲染: 支持插槽、Render函数、默认渲染多种方式
  5. 状态管理: 使用 provide/inject 实现跨模块状态共享
  6. 国际化: 完整的多语言支持
  7. 响应式: 自动高度、容器尺寸监听等响应式特性

技术亮点

  • Composition API: 充分利用 Vue 3 组合式 API
  • Hook 系统: 逻辑复用和关注点分离
  • 依赖注入: 优雅的状态共享机制
  • 性能优化: 虚拟滚动、计算缓存、事件防抖
  • 扩展性: 插件化设计,易于功能扩展

BaseTable 为项目提供了统一、高效、易用的表格解决方案,是整个系统中不可或缺的核心UI组件。