如上图所示,想要实现上图这个表格,我们有两种思路,第一直接写死,使用table tr td 第二种动态生成,这里我选用的是第二种思路,借用el-table 组件合并单元格的思路进行实现。
简单介绍下 el-table 合并单元格的用法
在 Element UI 的 el-table
组件中,要合并单元格,可以使用 table
组件的 span-method
属性。这个属性接受一个方法,该方法的返回值决定单元格应该如何被合并。
span-method
方法会传入一个参数,该参数是一个对象,包含 row
、column
、rowIndex
和 columnIndex
四个字段,表示当前单元格的行对象、列对象、行索引和列索引。
该方法应该返回一个数组,数组的两个元素分别指定需要合并的行数和列数。如果你不需要合并当前的单元格,则返回一个 [1, 1]
的数组。
这里是一个简单的例子,说明如何使用 span-method
来合并表格单元格:
html
<template>
<el-table :data="tableData" border style="width: 100%" :span-method="arraySpanMethod">
<el-table-column prop="date" label="日期" width="150"></el-table-column>
<el-table-column prop="name" label="姓名" width="150"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [
{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
// ...其他数据
]
};
},
methods: {
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
if (rowIndex % 2 === 0) {
if (columnIndex === 0) {
// 例如:合并行索引为偶数的第一列的单元格
return [2, 1];
}
}
return [1, 1];
}
}
};
</script>
在上述例子中,arraySpanMethod
方法会检查当前的行索引 rowIndex
是否是偶数,如果是并且当前是第一列(columnIndex === 0
),它会合并当前行和下一行的这一列单元格。
记住,合并单元格时要确保其他被合并的单元格(即除了第一个单元格以外的单元格)返回 [0, 0]
。
请注意,合并单元格可能会复杂化表格的设计,尤其是当涉及动态行数据和多个合并条件时。务必仔细规划你的合并策略并测试确保没有遗漏任何情况。
我们通过分析设计原型图,发现有些表头下是一列,有些是两列,这里可以使用 el-table-conlumn 嵌套的写法实现。 粘上实现代码=》
js
<template>
<div class="table">
<el-table
:data="tableData"
:span-method="objectSpanMethods"
border
class="custom-hide-second-row"
style="width: 100%"
>
<!-- 需要合并的列 -->
<el-table-column
v-for="(el, i) in colConfigs"
:key="i"
align="center"
:label="el.label"
>
<el-table-column :prop="el.prop[0]" align="center"> </el-table-column>
<el-table-column v-if="el.prop[1]" align="center" :prop="el.prop[1]">
</el-table-column>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "Table",
props: {
tableData: {
type: Array,
default: () => {
return [];
},
},
colConfigs: {
type: Array,
default: () => {
return [];
},
},
mergeCols: {
type: Array,
default: null,
},
},
data() {
return {
tableMergeIndex: [],
};
},
methods: {
objectSpanMethods({ row, column, rowIndex, columnIndex }) {
const key = columnIndex + "_" + rowIndex;
// console.log(this.tableMergeIndex);
if (this.tableMergeIndex[key]) {
return this.tableMergeIndex[key];
}
},
newTableMergeData() {
for (let i = 0; i < this.tableData.length; i++) {
for (let j = 0; j < this.mergeCols.length; j++) {
// 初始化行、列坐标信息
let rowIndex = 1;
let columnIndex = 1;
// 比较横坐标左方的第一个元素
if (
j > 0 &&
this.tableData[i][this.mergeCols[j]["name"]] ===
this.tableData[i][this.mergeCols[j - 1]["name"]]
) {
columnIndex = 0;
}
// 比较纵坐标上方的第一个元素
if (
i > 0 &&
this.tableData[i][this.mergeCols[j]["name"]] ===
this.tableData[i - 1][this.mergeCols[j]["name"]]
) {
rowIndex = 0;
}
// 比较横坐标右方元素
if (columnIndex > 0) {
columnIndex = this.onColIndex(
this.tableData[i],
j,
j + 1,
1,
this.mergeCols.length,
);
}
// 比较纵坐标下方元素
if (rowIndex > 0) {
rowIndex = this.onRowIndex(
this.tableData,
i,
i + 1,
1,
this.mergeCols[j]["name"],
);
}
const key = this.mergeCols[j]["index"] + "_" + i;
this.tableMergeIndex[key] = [rowIndex, columnIndex];
}
}
},
/**
* 计算列坐标信息
* data 单元格所在行数据
* index 当前下标
* nextIndex 下一个元素坐标
* count 相同内容的数量
* maxLength 当前行的列总数
*/
onColIndex(data, index, nextIndex, count, maxLength) {
// 比较当前单元格中的数据与同一行之后的单元格是否相同
if (
nextIndex < maxLength &&
data[this.mergeCols[index]["name"]] ===
data[this.mergeCols[nextIndex]["name"]]
) {
return this.onColIndex(data, index, ++nextIndex, ++count, maxLength);
}
return count;
},
/**
* 计算行坐标信息
* data 表格总数据
* index 当前下标
* nextIndex 下一个元素坐标
* count 相同内容的数量
* name 数据的key
*/
onRowIndex(data, index, nextIndex, count, name) {
// 比较当前单元格中的数据与同一列之后的单元格是否相同
if (
nextIndex < data.length &&
data[index][name] === data[nextIndex][name]
) {
return this.onRowIndex(data, index, ++nextIndex, ++count, name);
}
return count;
},
},
};
</script>
父组件内使用:
js
<template>
<div class="main">
<Table
ref="tableRef"
:table-data="tableData"
:col-configs="column"
:merge-cols="mergeCols"
></Table>
</div>
</template>
data() {
return {
tableData: [
{
product: "农",
name_1: "耕",
count_1: "0.4",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "种植业",
},
{
product: "农",
name_1: "耕",
count_1: "0.4",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "权重",
},
{
product: "(权重)",
name_1: "耕",
count_1: "0.4",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "0.97",
},
{
product: "(权重)",
name_1: "耕",
count_1: "0.41",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "设施",
},
{
product: "0.61",
name_1: "耕",
count_1: "0.4",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "设施",
},
{
product: "0.61",
name_1: "耕",
count_1: "0.4",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "权重",
},
{
product: "0.61",
name_1: "耕",
count_1: "0.4",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "权重",
},
{
product: "0.61",
name_1: "耕",
count_1: "0.4",
name_2: "0.5",
count_2: "0.6",
name_3: "0.5",
count_3: "0.6",
name_4: "0.5",
count_4: "0.5",
index_1: "粮、油、棉、特色、设施",
index_2: "0.03",
},
],
// 表格的信息 需要合并的需要放在 children 中
column: [
{ prop: ["product"], label: "产业" },
{ prop: ["index_1", "index_2"], label: "指标简称" },
{ prop: ["name_1", "count_1"], label: "权重" },
{ prop: ["name_2", "count_2"], label: "2023年机械化水平" },
{ prop: ["name_3", "count_3"], label: "各产业综合机械化水平" },
{ prop: ["count_4"], label: "大农业综合机械化水平" },
],
// 需要合并的行列信息 index必须是table表格对应的下标 不能随意修改
mergeCols: [
{ index: 0, name: "product" },
{ index: 1, name: "index_1" },
{ index: 2, name: "index_2" },
{ index: 7, name: "name_3" },
{ index: 8, name: "count_3" },
{ index: 9, name: "count_4" },
// { index: 5, name: 'age' }
],
};
},
最后我们发现多出一行空白表头
去掉方法 是在table 组件mounted内调用
js
mounted() {
this.$nextTick(() => {
const secondRow = this.$el.querySelector(
".el-table__header-wrapper tr:nth-child(2)",
);
if (secondRow) {
secondRow.style.display = "none";
}
});
},
最终效果