紧接上文,这篇文章将展示最后的几个示例,下一篇文章则着重分析封装的element-table的实现原理。
示例15--表头分组(多级表头)
通过给列数据添加children属性,该属性也是一个对象数组,并和一级一样,添加列属性的配置即可实现表头分组(多级表头),也就是说我们的列数据可以是一个对象数组,同样的也可以是树形结构的数组。配置数据代码如下所示:
import { ElTableColumnProps } from '../components/tableProps';
const column: ElTableColumnProps[] = [
{
prop: "date",
width: 120,
label: "Date",
},
{
label: "Delivery Info",
children: [
{
prop: "name",
label: "Name",
},
{
label: "Address Info",
children: [
{
prop: "state",
label: "State",
},
{
prop: "city",
label: "City",
width: 120,
},
{
prop: "address",
label: "Address",
},
{
prop: "zip",
width: 120,
label: "Zip",
},
],
},
],
},
]
const tableData = [
/*数据忽略*/
]
html代码没什么变化,这样就可以实现一个多级表头了。
以上代码实现效果展示如下图所示:
示例16--修改表格的布局
通过设置table-layout的属性可以修改表格的布局,该属性的值可以是fixed或者auto,来看如下一个示例:
<el-radio-group v-model="tableLayout">
<el-radio-button value="fixed">fixed</el-radio-button>
<el-radio-button value="auto">auto</el-radio-button>
</el-radio-group>
<element-table
:column="column"
:data="tableData"
:table-layout="tableLayout"
></element-table>
ts代码如下所示:
import { ref } from "vue";
const tableLayout = ref<"fixed" | "auto">("fixed");
const column = [
// 列数据配置忽略
];
const tableData = [
// 数据忽略
];
以上代码实现效果展示如下图所示:
示例17--多选表格
通过给列数据配置一项type为'selection'的对象,则可以开启表格多选列,并且我们还可以通过表格实例提供的toggleRowSelection方法来设置对应的行数据是否选中,该方法支持传入2个参数,第一个参数为单行数据,第二个参数是一个布尔值,表示是否选中,同样我们也可以使用表格实例提供的clearSelection方法,清除所有选中。
通过selection-change事件可以监听选中事件,该事件方法返回选中项值,应该是一个数组。
接下来我们来看这个示例,我们用一个ref存储表格实例,然后一般多选列都是放在第一列,因此表格列数据的第一项就是配置的多选列对象。
html代码如下所示:
ref="multipleTableRef"
:data="tableData"
style="width: 100%"
:column="column"
@selection-change="handleSelectionChange"
>
<template #default="scope">Date:{{ scope.row.date }}</template>
</element-table>
<div style="margin-top: 20px">
<el-button @click="toggleSelection([tableData[1], tableData[2]])"
>Toggle selection status of second and third rows</el-button
>
<el-button @click="toggleSelection()">Clear selection</el-button>
</div>
ts代码如下所示:
import { ref } from "vue";
import type { ElTable } from "element-plus";
interface User {
date: string;
name: string;
address: string;
}
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const multipleSelection = ref<User[]>([]);
const toggleSelection = (rows?: User[]) => {
console.log("🚀 ~ file: MultiSelectTable.vue ~ line 32 ~ toggleSelection ~ rows", rows);
if (rows) {
rows.forEach(row => multipleTableRef.value!.toggleRowSelection(row, false));
} else {
multipleTableRef.value!.clearSelection();
}
};
const handleSelectionChange = (val: User[]) => {
multipleSelection.value = val;
};
const column = [
// 这里是配置多选框
{
type: "selection",
width: 50,
},
{
prop: "date",
label: "Date",
width: 120,
slotName: "default",
},
{
prop: "name",
label: "Name",
width: 120,
},
{
prop: "address",
label: "Address",
// 表示如果地址名太长,显示不下,会出现提示框
"show-overflow-tooltip": true,
},
];
const tableData: User[] = [
// 数据忽略
];
以上代码实现效果展示如下图所示:
示例18--合并行或列
通过给table绑定span-method事件可以实现表格的合并行或者列功能,该事件方法的参数是一个对象,分别是行数据,列数据,与对应的行索引值和列索引值。即以下ts类型代码所示:
import type { TableColumnCtx } from "element-plus/es/components/table/src/table-column/defaults";
interface SpanMethodProps {
row: User;
column: TableColumnCtx<User>;
rowIndex: number;
columnIndex: number;
}
该事件方法可以返回一个包含两个元素的数组,第一个元素代表 rowspan
,第二个元素代表 colspan
。 也可以返回一个键名为 rowspan
和 colspan
的对象。
来看示例具体代码如下所示:
<div>
<element-table
:column="column"
:data="tableData"
:span-method="arraySpanMethod"
border
style="width: 100%"
></element-table>
<element-table
:column="column2"
:data="tableData"
:span-method="objectSpanMethod"
border
style="width: 100%; margin-top: 20px"
></element-table>
</div>
ts代码如下所示:
// ...
// 返回数组
const arraySpanMethod = ({ rowIndex, columnIndex }: SpanMethodProps) => {
if (rowIndex % 2 === 0) {
if (columnIndex === 0) {
return [1, 2];
} else if (columnIndex === 1) {
return [0, 0];
}
}
};
// 返回对象
const objectSpanMethod = ({ rowIndex, columnIndex }: SpanMethodProps) => {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1,
};
} else {
return {
rowspan: 0,
colspan: 0,
};
}
}
};
const column = [
// 略
];
const column2 = [
// 略
];
const tableData: User[] = [
// 略
];
以上代码实现效果展示如下图所示:
示例19--表格单选
选择单行数据时使用色块表示。
Table 组件提供了单选的支持, 只需要配置 highlight-current-row
属性即可实现单选。 之后由 current-change
事件来管理选中时触发的事件,它会传入 currentRow
,oldCurrentRow
。 如果需要显示索引,可以增加一列数据配置,设置 type
属性为 index
即可显示从 1 开始的索引号。
同时表格实例也提供了setCurrentRow方法来设置当前选中,如果传入对应行数据,则会选中对应行,如果不传,则会取消对应选中。
来看具体的示例代码,如下所示:
<element-table
ref="singleTableRef"
:data="tableData"
:column="column"
highlight-current-row
style="width: 100%"
@current-change="handleCurrentChange"
></element-table>
<div style="margin-top: 20px">
<el-button @click="setCurrent(tableData[1])">Select second row</el-button>
<el-button @click="setCurrent()">Clear selection</el-button>
</div>
ts代码如下所示:
import { ref } from "vue";
import type { ElTable } from "element-plus";
const column = [
// 略
];
// ...
// 核心逻辑在这里
const currentRow = ref();
const singleTableRef = ref<InstanceType<typeof ElTable>>();
const setCurrent = (row?: User) => {
singleTableRef.value!.setCurrentRow(row);
};
const handleCurrentChange = (val: User | undefined) => {
currentRow.value = val;
};
const tableData: User[] = [
// 略
];
以上代码实现效果展示如下图所示:
示例20--排序
在列中设置 sortable
属性即可实现以该列为基准的排序, 接受一个 Boolean
,默认为 false
。 可以通过 Table 的 default-sort
属性设置默认的排序列和排序顺序。 可以使用 sort-method
或者 sort-by
使用自定义的排序规则。 如果需要后端排序,需将 sortable
设置为 custom
,同时在 Table 上监听 sort-change
事件, 在事件回调中可以获取当前排序的字段名和排序顺序,从而向接口请求排序后的表格数据。 我们还可以使用了 formatter
属性,它用于格式化指定列的值, 接受一个 Function
,会传入两个参数:row
和 column
, 可以根据自己的需求进行处理。
来看一个简单的示例,如下所示:
<element-table
:data="tableData"
:column="column"
:default-sort="{ prop: 'date', order: 'descending' }"
style="width: 100%"
></element-table>
ts代码如下所示:
interface User {
date: string;
name: string;
address: string;
}
const formatter = (row: User) => row.address;
const column = [
{
prop: "date",
label: "Date",
width: 120,
// sortable还可以设置为custom
sortable: true,
},
{
prop: "name",
label: "Name",
width: 120,
},
{
prop: "address",
label: "Address",
formatter,
},
];
const tableData: User[] = [
// 略
];
以上代码实现效果展示如下图所示:
示例21--带状态表格
我们还可将表格内容 highlight 显示,方便区分「成功、信息、警告、危险」等内容。
具体就是通过指定 Table 组件的 row-class-name
属性来为 Table 中的某一行添加 class, 这样就可以自定义每一行的样式了。
如以下这个示例:
<element-table :column="column" :data="data" :row-class-name="tableRowClassName"></element-table>
ts代码如下所示:
const data = [
// 略
]
const column = [
// 略
]
function tableRowClassName({ rowIndex }: { rowIndex: number }) {
if (rowIndex === 1) {
return "warning-row";
} else if (rowIndex === 3) {
return "success-row";
}
return "";
}
css代码如下所示:
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
以上代码实现效果展示如下图所示:
示例22--斑马纹表格
使用带斑马纹的表格,可以更容易区分出不同行的数据。
stripe
可以创建带斑马纹的表格。 如果 true
, 表格将会带有斑马纹。
示例代码如下所示:
<element-table stripe :column="column" :data="tableData" />
ts代码略,以上代码实现效果展示如下图所示:
示例23--表尾合计行
若表格展示的是各类数字,可以在表尾显示各列的合计。
将 show-summary
设置为true
就会在表格尾部展示合计行。 默认情况下,对于合计行,第一列不进行数据求合操作,而是显示「合计」二字(可通过sum-text
配置),其余列会将本列所有数值进行求合操作,并显示出来。当然,你也可以定义自己的合计逻辑。使用 summary-method
并传入一个方法,这个方法的参数返回一个配置列和表格数据的对象,方法结果返回一个数组,这个数组中的各项就会显示在合计行的各列中。
来看具体的示例代码:
<element-table
:column="column"
:data="tableData"
border
show-summary
style="width: 100%"
></element-table>
<element-table
:column="column2"
:data="tableData"
border
height="200"
:summary-method="getSummaries"
show-summary
style="width: 100%; margin-top: 20px"
></element-table>
ts代码如下所示:
import type { TableColumnCtx } from "element-plus/es/components/table/src/table-column/defaults";
interface Product {
id: string;
name: string;
amount1: string;
amount2: string;
amount3: number;
}
interface SummaryMethodProps<T = Product> {
columns: TableColumnCtx<T>[];
data: T[];
}
// 核心代码
const getSummaries = (param: SummaryMethodProps) => {
const { columns, data } = param;
const sums: string[] = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = "Total Cost";
return;
}
const values = data.map(item => Number(item[column.property]));
if (!values.every(value => isNaN(value))) {
sums[index] = `$ ${values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0)}`;
} else {
sums[index] = "N/A";
}
});
return sums;
};
const column = [
// 略
];
const column2 = [
// 略
];
const tableData: Product[] = [
// 略
];
以上代码实现效果展示如下图所示:
示例24--树形数据与懒加载
当 row 中包含 children
字段时,被视为树形数据。渲染嵌套数据需要 prop 的 row-key
。 此外,子行数据可以异步加载。设置 Table 的lazy
属性为 true 与加载函数 load
。 通过指定 row 中的hasChildren
字段来指定哪些行是包含子节点。 children
与hasChildren
都可以通过 tree-props
配置。同样的也可以设置default-expand-all属性,表示默认展开所有数据。
来看示例代码如下所示:
<div>
<element-table
:column="column"
:data="tableData"
style="width: 100%; margin-bottom: 20px"
row-key="id"
border
default-expand-all
></element-table>
<element-table
:column="column2"
:data="tableData1"
style="width: 100%"
row-key="id"
border
lazy
:load="load"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
</element-table>
</div>
ts代码如下所示:
interface User {
id: number;
date: string;
name: string;
hasChildren?: boolean;
children?: User[];
}
// 加载函数
const load = (_row: User, _treeNode: unknown, resolve: (date: User[]) => void) => {
setTimeout(() => {
resolve([
{
id: 31,
date: "2016-05-01",
name: "wangxiaohu",
},
{
id: 32,
date: "2016-05-01",
name: "wangxiaohu",
},
]);
}, 1000);
};
const column = [
// ...
];
const column2 = [
//...
];
const tableData: User[] = [
//...
{
id: 3,
date: "2016-05-01",
name: "wangxiaohu",
children: [
{
id: 31,
date: "2016-05-01",
name: "wangxiaohu",
},
{
id: 32,
date: "2016-05-01",
name: "wangxiaohu",
},
],
},
//...
];
const tableData1: User[] = [
// ...
{
id: 3,
date: "2016-05-01",
name: "wangxiaohu",
hasChildren: true,
},
// ...
];
以上代码实现效果展示如下图所示:
所有示例介绍完毕,下一篇文章我将介绍封装的实现原理,让我们下篇文章再见。