iview table 行列合并
1. 需求
后台获取的数据,前端渲染时,如果同一列相邻的数据相同,则合并成一个单元格。
2 官方示例
设置属性 span-method
可以指定合并行或列的算法。
该方法参数为 4 个对象:
- row: 当前行
- column: 当前列
- rowIndex: 当前行索引
- columnIndex: 当前列索引
该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。
<template>
<Table :columns="columns" :data="data" border :span-method="handleSpan"></Table>
</template>
<script>
export default {
data () {
return {
columns: [
{
title: 'Date',
key: 'date'
},
{
title: 'Name',
key: 'name'
},
{
title: 'Age',
key: 'age'
},
{
title: 'Address',
key: 'address'
}
],
data: [
{
name: 'John Brown',
age: 18,
address: 'New York No. 1 Lake Park',
date: '2016-10-03'
},
{
name: 'Jim Green',
age: 24,
address: 'London No. 1 Lake Park',
date: '2016-10-01'
},
{
name: 'Joe Black',
age: 30,
address: 'Sydney No. 1 Lake Park',
date: '2016-10-02'
},
{
name: 'Jon Snow',
age: 26,
address: 'Ottawa No. 2 Lake Park',
date: '2016-10-04'
}
]
}
},
methods: {
handleSpan ({ row, column, rowIndex, columnIndex }) {
if (rowIndex === 0 && columnIndex === 0) {
return [1, 2];
} else if (rowIndex === 0 && columnIndex === 1) {
return [0, 0];
}
if (rowIndex === 2 && columnIndex === 0) {
return {
rowspan: 2,
colspan: 1
};
} else if (rowIndex === 3 && columnIndex === 0) {
return {
rowspan: 0,
colspan: 0
};
}
}
}
}
</script>
注意:合并和被合并的区别,返回值不是[0,0]的,其内容显示在合并后的单元格中。返回值是[0,0]的是被合并的单元格,内容相当于删除
效果图
3 动态合并
handleSpan 实现
/**
* 合并行或列的算法
* @param row 当前行
* @param column 当前列
* @param rowIndex 当前行索引
* @param columnIndex 当前列索引
* @returns {{colspan: (number), rowspan: *}}
*/
handleSpan({ row, column, rowIndex, columnIndex }) {
// 姓名合并
if (columnIndex === 0) {
// 二维数组存储的数据 取出
const _row = this.nameMerges[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
// 地址合并
if (columnIndex === 2) {
// 二维数组存储的数据 取出
const _row = this.addrMerges[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
if (columnIndex === 4) {
// 操作列序号
// 二维数组存储的数据 取出
const _row = this.opMerges[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
},
处理数据
formatData() {
this.nameMerges = this.getMerges(this.resData, "name");
this.addrMerges = this.getMerges(this.resData, "address");
this.opMerges = [...this.nameMerges]; // 复制name的合并信息
console.log(this.opMerges);
},
/**
*
* @param data 数据列表
* @param key 将要合并的对比字段
* @returns {*[]}
*/
getMerges(data, key) {
let spanArr = []
let pos = 0
// 遍历数据
data.forEach((item, index) => {
// 判断是否是第一项
if (index === 0) {
spanArr.push(1)
pos = 0
} else {
// 不是第一项时,就根据标识去存储
if (data[index][key] === data[index - 1][key]) {
// 查找到符合条件的数据时每次要把之前存储的数据+1
spanArr[pos] += 1
spanArr.push(0)
} else {
// 没有符合的数据时,要记住当前的index
spanArr.push(1)
pos = index
}
}
})
return spanArr
},
从后台拿到数据后,先调用下处理数据的方法
this.formatData();
完整代码示例
<template>
<Table
class="border-table"
:columns="columns"
:data="resData"
border
:span-method="handleSpan"
>
<!-- 操作 -->
<template slot="xm" slot-scope="{ row, index }">
<a href="">{{ row.name }}</a>
</template>
<!-- 操作 -->
<template slot="action" slot-scope="{ row, index }">
<div class="tableBtnBox enniu">
<div class="tableBtn">
<Button class="cz_btn" type="success" size="small">查看详情</Button>
</div>
</div>
</template>
</Table>
</template>
<script>
export default {
data() {
return {
columns: [
{
title: "Name",
// key: "name",
slot: "xm",
},
{
title: "Age",
key: "age",
},
{
title: "Address",
key: "address",
},
{
title: "Desc",
key: "desc",
},
{
title: "操作",
align: "center",
slot: "action",
},
],
resData: [
{
"id": 1,
"name": "John Doe",
"age": 32,
"address": "202 Main Street, New York, NY",
"desc": "Data engineer"
},
{
"id": 2,
"name": "Lisa Wang",
"age": 28,
"address": "99 Long Road, Shanghai, CN",
"desc": "Product manager"
},
{
"id": 3,
"name": "Jane Smith",
"age": 35,
"address": "99 Long Road, Shanghai, CN",
"desc": "Software architect"
},
{
"id": 4,
"name": "Jane Smith",
"age": 29,
"address": "51 South Avenue, Miami, FL",
"desc": "UI designer"
},
{
"id": 5,
"name": "Tom Brown",
"age": 29,
"address": "1675 Park Avenue, Paris, FR",
"desc": "Backend developer"
},
{
"id": 6,
"name": "Alice Chen",
"age": 30,
"address": "20 Surry Street, London, UK",
"desc": "DevOps engineer"
}
],
nameMerges: [],
addrMerges: [],
opMerges: [],
};
},
methods: {
/**
* 合并行或列的算法
* @param row 当前行
* @param column 当前列
* @param rowIndex 当前行索引
* @param columnIndex 当前列索引
* @returns {{colspan: (number), rowspan: *}}
*/
handleSpan({ row, column, rowIndex, columnIndex }) {
// 姓名合并
if (columnIndex === 0) {
// 二维数组存储的数据 取出
const _row = this.nameMerges[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
// 地址合并
if (columnIndex === 2) {
// 二维数组存储的数据 取出
const _row = this.addrMerges[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
if (columnIndex === 4) {
// 操作列序号
// 二维数组存储的数据 取出
const _row = this.opMerges[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
},
formatData() {
this.nameMerges = this.getMerges(this.resData, "name");
this.addrMerges = this.getMerges(this.resData, "address");
this.opMerges = [...this.nameMerges]; // 复制name的合并信息
console.log(this.opMerges);
},
/**
*
* @param data 数据列表
* @param key 将要合并的对比字段
* @returns {*[]}
*/
getMerges(data, key) {
// 页面展示的数据,不一定是全部的数据,所以每次都清空之前存储的 保证遍历的数据是最新的数据。以免造成数据渲染混乱
let spanArr = [];
let pos = 0;
// 遍历数据
data.forEach((item, index) => {
// 判断是否是第一项
if (index === 0) {
spanArr.push(1);
pos = 0;
} else {
// 不是第一项时,就根据标识去存储
if (data[index][key] === data[index - 1][key]) {
// 查找到符合条件的数据时每次要把之前存储的数据+1
spanArr[pos] += 1;
spanArr.push(0);
} else {
// 没有符合的数据时,要记住当前的index
spanArr.push(1);
pos = index;
}
}
});
return spanArr;
},
},
mounted() {
this.formatData();
},
};
</script>
<style scoped>
</style>
效果图
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!