# Table 表格组件
基于 ElementUI el-table 封装,支持通过配置数组渲染表格列(支持多级表头),内置分页组件。
# 基础用法
<template>
<div>
<ctc-table
:data="tableData"
:column="columns"
>
<!-- 自定义列插槽 -->
<template #status="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? "启用" : "禁用" }}
</el-tag>
</template>
<!-- 操作列 -->
<template #action="{ row }">
<el-button type="text" @click="handleEdit(row)">编辑</el-button>
</template>
</ctc-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{ name: '张三', age: 18, status: 1 },
{ name: '李四', age: 25, status: 0 },
{ name: '王五', age: 30, status: 1 }
],
total: 3,
currentPage: 1,
pageSize: 10,
columns: [
{ label: "姓名", prop: "name" },
{ label: "年龄", prop: "age" },
{ label: "状态", prop: "status" },
{ label: "操作", prop: "action", width: 200 },
],
};
}
};
</script>
# 属性 (Props)
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| data | 显示的数据 | Array | [] |
| column | 表格列配置数组 (见下文) | Array | [] |
| pagination | 是否显示分页 | Boolean | false |
| total | 总条目数 (用于分页) | Number | 0 |
| currentPage | 当前页码 (支持 .sync 修饰符) | Number | - |
| pageSize | 每页显示条目个数 (支持 .sync 修饰符) | Number | - |
| pageStyle | 分页样式 | Object/String | - |
| merge | 需要合并的列字段数组 (如 ['name', 'type']) | Array | - |
| spanMethod | 合并行或列的计算方法 (同 el-table) | Function | - |
| autoHeight | 是否自动适应父容器高度 | Boolean | true |
| loading | 加载状态 | Boolean | false |
| draggable | 是否开启行拖拽 | Boolean | false |
透传属性: 支持 el-table 的所有属性 (如 height, stripe, border 等)。
# 事件 (Events)
| 事件名 | 说明 | 参数 |
|---|---|---|
| current-change (或 currentChange) | 分页 - 当前页改变时触发 | currentPage |
| update:currentPage | 分页 - 当前页同步更新 | currentPage |
| size-change (或 sizeChange) | 分页 - 每页条数改变时触发 | pageSize |
| update:pageSize | 分页 - 每页条数同步更新 | pageSize |
| prev-click (或 prevClick) | 分页 - 点击上一页 | currentPage |
| next-click (或 nextClick) | 分页 - 点击下一页 | currentPage |
| drag-end | 拖拽结束时触发 | { oldIndex, newIndex, row } |
透传事件: 支持 el-table 的所有事件 (如 sort-change, selection-change 等)。
注:为了向后兼容,分页相关的事件同时支持短横线(官方推荐)和驼峰命名(如 @current-change 和 @currentChange 均可触发)。对于数据双向绑定,推荐使用 .sync 修饰符(如 :current-page.sync="page.current")。
# Column 配置对象
column 数组中的每个对象支持以下属性:
| 属性 | 说明 | 类型 |
|---|---|---|
| label | 显示的标题 | String |
| prop | 对应列内容的字段名 (也作为插槽名) | String |
| width | 列宽度 | String |
| minWidth | 最小列宽 | String |
| fixed | 列是否固定 (true, left, right) | Boolean/String |
| sortable | 对应列是否可以排序 | Boolean |
| align | 对齐方式 (left/center/right) | String |
| headerAlign | 表头对齐方式 | String |
| children | 多级表头上配置 (嵌套 Column 对象) | Array |
| formatter | 格式化内容 function(row, column, cellValue, index) | Function |
| renderHeader | 自定义表头渲染函数 (JSX) | Function |
| slotHeader | 自定义表头插槽名 (在 template 中使用该名称定义插槽) | String |
| slotBody | 自定义列内容插槽名 (默认使用 prop 值作为插槽名) | String |
| labelClassName | 标签的类名 | String |
| columnKey | 对应列的唯一标识 (用于解决 prop 重复时的 key 冲突) | String |
透传属性: 支持 el-table-column 的所有属性 (如 className, show-overflow-tooltip 等),将直接透传给组件。
注意:prop 既是数据字段,也是自定义插槽的名称。如果在 ctc-table 内部写了 <template #xxx="scope">,则会优先使用插槽渲染该列。当多个列使用相同的 prop 时,请务必设置唯一的 columnKey 以避免 Vue 的 key 冲突告警。
# 插槽 (Slots)
| 插槽名 | 说明 |
|---|---|
| [column.prop] | 动态列插槽,名称对应 column 配置中的 prop |
| [column.slotHeader] | 动态表头插槽,名称对应 column 配置中的 slotHeader |
| append | 插入至表格最后一行之后的内容 |
| empty | 空数据时显示的文本内容 |
| pagination | 分页组件内部自定义插槽 |
# 插槽作用域参数
列插槽和表头插槽除了 Element UI 原有的作用域参数外,还额外提供了 config 属性,指向你在 column 数组中定义的原始配置对象,可通过它访问自定义属性。
| 参数 | 说明 |
|---|---|
| row | 当前行数据 (仅列插槽) |
| column | Element UI 内部的 column 对象 (仅含标准属性) |
| $index | 当前行索引 (仅列插槽) |
| config | 你定义的原始 column 配置对象,可访问自定义属性如 config.unit |
# 自定义表头插槽 (slotHeader)
通过 slotHeader 可以在 template 中自定义表头内容,而无需编写 JSX。插槽作用域中的 config 指向原始的 column 配置对象,可以在其中维护自定义属性。
<template>
<ctc-table
:data="tableData"
:column="columns"
>
<template #header-unit="{ config }">
<el-radio-group v-model="config.unit" size="mini">
<el-radio label="1">mg/m³</el-radio>
<el-radio label="2">g/m³</el-radio>
</el-radio-group>
</template>
<template #status="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? "启用" : "禁用" }}
</el-tag>
</template>
</ctc-table>
</template>
<script>
export default {
data() {
return {
tableData: [
{ name: '张三', age: 18, status: 1 },
{ name: '李四', age: 25, status: 0 },
{ name: '王五', age: 30, status: 1 }
],
columns: [
{ label: "姓名", prop: "name" },
{ label: "年龄", prop: "age" },
{ label: "状态", prop: "status" },
{ label: "单位", prop: "unit", slotHeader: "header-unit", unit: "1" },
],
};
},
};
</script>
# 行拖拽 (Row Dragging)
通过设置 draggable 属性为 true 开启行拖拽功能。拖拽结束时会触发 drag-end 事件,返回被拖拽行的索引信息。
<template>
<div>
<ctc-table
draggable
:data="tableData"
:column="columns"
:total="0"
@drag-end="handleDragEnd"
>
</ctc-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{ id: 1, name: '张三', date: '2023-01-01', address: '上海市普陀区金沙江路 1518 弄' },
{ id: 2, name: '李四', date: '2023-01-02', address: '上海市普陀区金沙江路 1517 弄' },
{ id: 3, name: '王五', date: '2023-01-03', address: '上海市普陀区金沙江路 1519 弄' },
{ id: 4, name: '赵六', date: '2023-01-04', address: '上海市普陀区金沙江路 1516 弄' }
],
columns: [
{ label: "ID", prop: "id", width: 80 },
{ label: "日期", prop: "date" },
{ label: "姓名", prop: "name" },
{ label: "地址", prop: "address" },
],
};
},
methods: {
handleDragEnd({ oldIndex, newIndex, row }) {
console.log('拖拽结束:', oldIndex, newIndex, row)
// 交换数据 (简单实现)
const targetRow = this.tableData.splice(oldIndex, 1)[0]
this.tableData.splice(newIndex, 0, targetRow)
this.$message.success(`行从 ${oldIndex} 拖拽到 ${newIndex}`)
}
}
};
</script>