在近日的开发中遇到了需要将antd表格的列合并与插槽合并使用的问题,现整理如下:
antd行列合并
关于antd行列合并的实现,antd官方文档中有详细介绍:
表头只支持列合并,使用 column 里的 colSpan 进行设置。
表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。
本文以行合并(纵向合并)为例:
关于rowSpan属性值的获取,我写了一个方法,仅供参考:
/*
** data - 即table的dataSource
** index - 需要被合并的属性名
*/
function getRowSpanList (data, index) {
var RowSpanList = new Array(data.length)
var x = ''
var count = 0
var startindex = 0
for (var i = 0; i < data.length;i++) {
var val = data[i][index]
if (i === 0 ) {
x = val
count = 1
RowSpanList[0] = 1
} else {
if (val === x) {
count ++
RowSpanList[startindex] = count
RowSpanList[i] = 0
} else {
count = 1
x = val
startindex = i
RowSpanList[i] = 1
}
}
}
return RowSpanList
}
在table的column的相应属性中做配置,此处以class为例:
column: [{
title: '类型',
key: 'class',
dataIndex: 'class'
customRender: (text, record, index) => {
return {
children: text,
attrs: {
rowSpan: record.classRowSpanValue //由上文中的方法获取,仅供参考
}
}
}
},...]
再将对应的rowSpan值赋给dataSource中相应对象即可:
var classRowSpanList = getRowSpanList(dataSource, 'class')
for (var i = 0;i < dataSource.length; i++) {
dataSource[i].classRowSpanValue = classRowSpanList[i]
}
至此已可以实现简单的行合并,效果如下:
如果需要实现下图所示的有主从关系的行合并(即不同的合并项之间有明显的先后关系,红色框的合并受蓝色框限定):
需要结合主要属性对次要属性设置rowSpan值,方法如下,仅供参考:
/*
** data - 即table的dataSource
** index - 需要被合并的属性名
** formatArr - 合并主要项的rowSpan数组,通过getRowSpanList方法获取
*/
function getRowSpanListByFormatter (data, index, formatArr) {
var newArray = new Array(data.length)
var startIndex, endIndex, val, counter
for(var i = 0; i < data.length; i++) {
if (formatArr[i] === 1) {
newArray[i] = 1
} else if (formatArr[i] === 0) {
continue
} else {
// 内层遍历
startIndex = i
endIndex = i + formatArr[i] - 1
val = data[startIndex][index]
counter = 1
for(var j = i + 1; j <= endIndex; j++) {
var currentVal = data[j][index]
if (val === currentVal) {
// 当前位置的colspan值为0,计数器++
newArray[j] = 0
counter++
newArray[startIndex] = counter
} else {
// 上次的col数量
newArray[startIndex] = counter
// 对比数据重置
startIndex = j
val = data[startIndex][index]
counter = 1
if (j === endIndex) {
newArray[j] = counter
}
}
}
}
}
return newArray
}
再将对应的rowSpan值赋给dataSource中相应对象即可。
列合并同理。
行列合并与插槽同时使用
普通的table插槽是在column对象中配置scopedSlots: { customRender: 'xxx' }
,并在<a-table>
标签中写相应的代码实现的,与此处关系不大,不做过多的介绍。
上文中提到,行列合并时要对customRender做配置,相应单元格的重写则需要写在customRender返回的children中,使用的是类似React的语法:
customRender: (text, record, index) => {
return {
children: text, // 这里
attrs: {
rowSpan: 2
}
}
}
注意,在同时使用行列合并与插槽功能时column应放在组件的data()中,否则渲染会出错,具体原因我也不清楚,期待大佬解答
例子如下,我希望在实现行合并的同时对超出单元格的内容做省略处理,并使用a-tooltip
组件实现鼠标悬浮显示:
column:[{
title: '类型',
key: 'class',
dataIndex: 'class',
customRender: (text,record) => {
var childrenVal
if (record.scZoneRowSpan === 0) {
// 为被合并的项,不被显示,他的内容意义不大
childrenVal = ''
} else if (record.scZoneRowSpan === 1) {
// 不合并、单独显示的项,超出单元格做省略处理
// 插槽与HTML代码相同,只是Vue中的{{}} 要换成 {}
// 在children中的HTML已不支持v-if等Vue指令所以需要判断一下
if (text && text.length >= 9) {
childrenVal = (
<a-tooltip>
<template slot="title">{text}</template>
<div style="width: 133px;height:21px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">{text}</div>
</a-tooltip>)
} else {
childrenVal = (<span> {text} </span>)
}
} else if (record.scZoneRowSpan >= 2) {
// 合并项,因为有足够的高度,可以直接显示
childrenVal = text
}
return {
children: childrenVal,
attrs: {
rowSpan: record.scZoneRowSpan
}
}
}
}, ...]
效果如图:
如果需要对插槽中的元素添加事件:
childrenVal = (<div onclick={()=>{this.clickHandler(record)}} >{text}</div>)// 此处clickHandler正常写在methods中即可
总结
Ant Desing Vue 真难用
第一次写文章,也不知道讲清楚了没有,欢迎交流指导,各位大佬多多包涵。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。