BaseTable 组件使用文档
组件代码
vue
<template>
<div class="table-container">
<el-table ref="tableRef" :data="tableData" style="width: 100%" v-bind="tableProps" @selection-change="(newSelection) => emit('selection-change',newSelection)">
<!-- 表格插槽 -->
<template v-if="$slots.append" #append>
<slot name="append"></slot>
</template>
<template v-if="$slots.empty" #empty>
<slot name="empty"></slot>
</template>
<template v-for="item in columns" :key="item.prop">
<!-- 自定义列模板 -->
<template v-if="item.slot">
<el-table-column
v-bind="item"
:align="item.align"
:header-align="item.headerAlign"
:class-name="item.className"
:label-class-name="item.labelClassName"
:show-overflow-tooltip="item.showOverflowTooltip"
:sortable="item.sortable"
:sort-by="item.sortBy"
:sort-orders="item.sortOrders"
:resizable="item.resizable"
:formatter="item.formatter">
<!-- 列头部插槽 -->
<template v-if="$slots[`${item.prop}-header`]" #header="scope">
<slot :name="`${item.prop}-header`" v-bind="scope"></slot>
</template>
<!-- 过滤图标插槽 -->
<template v-if="$slots[`${item.prop}-filter-icon`]" #filter-icon="scope">
<slot :name="`${item.prop}-filter-icon`" v-bind="scope"></slot>
</template>
<template #default="scope">
<slot :name="item.slot" :row="scope.row" :index="scope.$index"></slot>
</template>
</el-table-column>
</template>
<!-- 操作列 -->
<template v-else-if="item.type === 'operation'">
<el-table-column
v-bind="item"
:align="item.align || 'center'"
:header-align="item.headerAlign"
:class-name="item.className"
:label-class-name="item.labelClassName"
:show-overflow-tooltip="item.showOverflowTooltip"
:resizable="item.resizable">
<!-- 操作列头部插槽 -->
<template v-if="$slots['operation-header']" #header="scope">
<slot name="operation-header" v-bind="scope"></slot>
</template>
<template #default="scope">
<el-button
v-for="btn in item.buttons"
:key="btn.text"
:type="btn.type || 'primary'"
:size="btn.size || 'small'"
@click="handleOperation(btn.action, scope.row, scope.$index)"
>
{{ btn.text }}
</el-button>
</template>
</el-table-column>
</template>
<!-- 普通列 -->
<template v-else>
<el-table-column
v-bind="item"
:align="item.align"
:header-align="item.headerAlign"
:class-name="item.className"
:label-class-name="item.labelClassName"
:show-overflow-tooltip="item.showOverflowTooltip"
:sortable="item.sortable"
:sort-by="item.sortBy"
:sort-orders="item.sortOrders"
:resizable="item.resizable"
:formatter="item.formatter">
<!-- 普通列头部插槽 -->
<template v-if="$slots[`${item.prop}-header`]" #header="scope">
<slot :name="`${item.prop}-header`" v-bind="scope"></slot>
</template>
</el-table-column>
</template>
</template>
</el-table>
</div>
</template>
<script setup>
import { defineProps, defineEmits, ref } from 'vue'
const tableRef = ref()
// 暴露表格实例的所有方法和属性给父组件
defineExpose({
// 表格实例的引用
tableRef,
// 表格实例的方法
clearSelection: () => tableRef.value?.clearSelection(),
toggleRowSelection: (row, selected) => tableRef.value?.toggleRowSelection(row, selected),
toggleAllSelection: () => tableRef.value?.toggleAllSelection(),
toggleRowExpansion: (row, expanded) => tableRef.value?.toggleRowExpansion(row, expanded),
setCurrentRow: (row) => tableRef.value?.setCurrentRow(row),
clearSort: () => tableRef.value?.clearSort(),
clearFilter: (columnKeys) => tableRef.value?.clearFilter(columnKeys),
doLayout: () => tableRef.value?.doLayout(),
sort: (prop, order) => tableRef.value?.sort(prop, order),
scrollTo: (options, yCoord) => tableRef.value?.scrollTo(options, yCoord),
setScrollTop: (top) => tableRef.value?.setScrollTop(top),
setScrollLeft: (left) => tableRef.value?.setScrollLeft(left),
// 表格实例的属性
getSelectionRows: () => tableRef.value?.getSelectionRows()
})
const props = defineProps({
// 表格数据
tableData: {
type: Array,
required: true,
default: () => []
},
// 列配置
columns: {
type: Array,
required: true,
default: () => [],
validator: (value) => {
return value.every(item => {
if (item.fixed) {
return ['left', 'right'].includes(item.fixed)
}
if (item.align) {
return ['left', 'center', 'right'].includes(item.align)
}
return true
})
}
},
// 表格属性
tableProps: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['operation','selection-change'])
// 处理操作按钮点击
const handleOperation = (action, row, index) => {
emit('operation', { action, row, index })
}
</script>
<style scoped>
.table-container {
padding: 20px;
}
</style>
组件介绍
BaseTable
是一个基于 Element Plus Table 组件的二次封装,提供了更简便的配置方式和完整的功能支持。
基础用法
最简单的示例
loading
完整示例
loading
API 文档
Props
参数 | 说明 | 类型 | 必填 | 默认值 |
---|---|---|---|---|
tableData | 表格数据 | Array | 是 | [] |
columns | 列配置 | Array | 是 | [] |
tableProps | 表格属性 | Object | 否 | {} |
Column 配置项
参数 | 说明 | 类型 | 必填 | 默认值 |
---|---|---|---|---|
prop | 列属性名 | string | 是 | - |
label | 列标签名 | string | 是 | - |
width | 列宽度 | number/string | 否 | - |
fixed | 列固定位置 | 'left'/'right' | 否 | - |
sortable | 是否可排序 | boolean | 否 | false |
slot | 自定义列插槽名 | string | 否 | - |
align | 对齐方式 | 'left'/'center'/'right' | 否 | 'left' |
formatter | 格式化函数 | Function | 否 | - |
showOverflowTooltip | 是否显示 tooltip | boolean | 否 | false |
type | 列类型,可选 'operation' | string | 否 | - |
buttons | 操作列按钮配置 | Array | 否 | - |
事件
事件名 | 说明 | 参数 |
---|---|---|
select | 当用户手动勾选数据行时触发 | selection, row |
select-all | 当用户手动勾选全选时触发 | selection |
selection-change | 当选择项发生变化时触发 | selection |
cell-mouse-enter | 当单元格 hover 进入时触发 | row, column, cell, event |
cell-mouse-leave | 当单元格 hover 离开时触发 | row, column, cell, event |
cell-click | 当单元格被点击时触发 | row, column, cell, event |
row-click | 当某一行被点击时触发 | row, column, event |
sort-change | 当表格的排序条件发生变化时触发 | column, prop, order |
filter-change | 当表格的筛选条件发生变化时触发 | filters |
operation | 当操作列按钮被点击时触发 | action, row, index |
方法
方法名 | 说明 | 参数 |
---|---|---|
clearSelection | 清空选择 | - |
toggleRowSelection | 切换某一行的选中状态 | row, selected |
toggleAllSelection | 切换所有行的选中状态 | - |
toggleRowExpansion | 切换某一行的展开状态 | row, expanded |
setCurrentRow | 设置某一行为当前行 | row |
clearSort | 清空排序条件 | - |
clearFilter | 清空过滤条件 | columnKeys |
doLayout | 重新布局表格 | - |
sort | 手动排序 | prop, order |
scrollTo | 滚动到指定位置 | options, yCoord |
setScrollTop | 设置垂直滚动条位置 | top |
setScrollLeft | 设置水平滚动条位置 | left |
插槽
插槽名 | 说明 | 作用域参数 |
---|---|---|
empty | 空数据时的内容 | - |
append | 表格底部内容 | - |
[prop]-header | 自定义表头 | column, $index |
[slot] | 自定义列内容 | row, column, $index |
注意事项
- 操作列的
type
必须设置为'operation'
- 使用自定义列时,需要在
columns
中设置slot
属性 - 自定义表头插槽名格式为
[prop]-header
- 所有的 Element Plus Table 的属性都可以通过
tableProps
传入
好的,我继续补充文档的其他部分:
高级用法示例
1. 多选表格
loading
2. 可展开行表格
loading
3. 带有筛选和排序的表格
loading
4. 自定义列模板和表头
loading
进阶配置
1. 表格属性(tableProps)完整配置
js
const tableProps = {
// 基础属性
border: true, // 是否带有纵向边框
stripe: true, // 是否为斑马纹表格
size: 'default', // 表格大小
fit: true, // 列的宽度是否自撑开
show-header: true, // 是否显示表头
highlight-current-row: true, // 是否高亮当前行
// 样式相关
height: '400px', // 表格高度
max-height: '600px', // 表格最大高度
row-class-name: 'row-class', // 行的 className
cell-class-name: 'cell-class', // 单元格的 className
// 功能相关
default-sort: { prop: 'id', order: 'descending' }, // 默认排序
default-expand-all: false, // 是否默认展开所有行
tree-props: { // 树形数据配置
hasChildren: 'hasChildren',
children: 'children'
},
// 事件处理
onSelect: (selection, row) => {},
onSelectAll: (selection) => {},
onSelectionChange: (selection) => {},
onCellMouseEnter: ({ row, column, cell, event }) => {},
onCellMouseLeave: ({ row, column, cell, event }) => {},
onCellClick: ({ row, column, cell, event }) => {},
onRowClick: (row, column, event) => {},
onSortChange: ({ column, prop, order }) => {},
onFilterChange: (filters) => {},
onHeaderDragend: (newWidth, oldWidth, column, event) => {}
}
2. 列配置(columns)完整选项
js
const columns = [
{
// 基础属性
prop: 'name', // 列属性名
label: '姓名', // 列标签名
width: 120, // 列宽度
minWidth: 100, // 最小列宽度
fixed: 'left', // 列固定位置
// 样式相关
align: 'center', // 对齐方式
headerAlign: 'center', // 表头对齐方式
className: 'custom-class', // 列的 className
labelClassName: 'label-class', // 表头的 className
// 功能相关
sortable: true, // 是否可排序
sortMethod: (a, b) => {}, // 自定义排序方法
sortBy: 'custom', // 指定排序的列
sortOrders: ['ascending', 'descending', null], // 排序顺序
// 筛选相关
filters: [ // 筛选选项
{ text: '选项1', value: 1 }
],
filterPlacement: 'bottom', // 筛选框的弹出位置
filterMultiple: true, // 是否多选
filterMethod: (value, row) => {}, // 筛选方法
// 自定义相关
slot: 'custom', // 使用自定义插槽
formatter: (row, column, cellValue, index) => {}, // 格式化函数
showOverflowTooltip: true, // 当内容过长被隐藏时显示 tooltip
// 操作列特殊配置
type: 'operation', // 操作列类型
buttons: [ // 操作按钮配置
{
text: '编辑',
type: 'primary',
size: 'small',
action: 'edit',
show: (row) => true, // 控制按钮显示
disabled: (row) => false // 控制按钮禁用
}
]
}
]
最佳实践
1. 数据加载和刷新
loading
2. 分页处理
loading
3. 表格工具栏
loading
常见问题
1. 表格不能自适应容器宽度
解决方案:
js
// 监听窗口大小变化
window.addEventListener('resize', () => {
baseTableRef.value?.doLayout()
})
// 在容器大小变化时调用
const handleResize = () => {
baseTableRef.value?.doLayout()
}
2. 表格高度计算问题
解决方案:
vue
<template>
<div class="table-container" ref="containerRef">
<BaseTable
ref="baseTableRef"
:table-props="{
height: tableHeight
}"
/>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue'
const containerRef = ref()
const tableHeight = ref(400)
const calculateTableHeight = async () => {
await nextTick()
if (containerRef.value) {
const containerHeight = containerRef.value.offsetHeight
tableHeight.value = containerHeight - 20 // 减去padding
}
}
onMounted(() => {
calculateTableHeight()
window.addEventListener('resize', calculateTableHeight)
})
</script>
3. 动态列处理
loading
性能优化建议
- 大数据量处理:
js
// 使用虚拟滚动
const tableProps = {
'virtual-scrolling': true,
'scroll-row-height': 48
}
- 避免不必要的重渲染:
js
// 使用 computed 处理数据
const processedData = computed(() => {
return tableData.value.map(item => ({
...item,
formattedDate: formatDate(item.date)
}))
})
- 合理使用
v-show
和v-if
:
vue
<!-- 频繁切换使用 v-show -->
<div v-show="loading" class="loading-mask" />
<!-- 条件渲染使用 v-if -->
<template v-if="hasPermission">
<el-button @click="handleEdit">编辑</el-button>
</template>