下面是动态表格的vue写法(未使用改变list的方法):
<el-table
ref="table"
:data="list"
:span-method="arraySpanMethod"
style="width: 100%;"
border
:header-cell-style="headerStyle"
>
<template v-for="column in columnDef">
<el-table-column
:key="column.prop"
:prop="column.prop"
:label="column.label"
align="center"
fixed
>
<template slot-scope="scope">
<span >
<span>{{ scope.row[scope.column.property] }} </span>
</span>
</template>
</el-table-column>
</template>
</el-table>
list是绑定的表格也即单元格数据,columnDef是表头数据,arraySpanMethod是单元格合并的方法,headerStyle是表头的方法。
columnSpanMethod() {
// 记录合并单元格的信息
this.span = [...this.columnDef];
this.columnDef.map((value, index, array) =>{
this.span[index] = 1; //将所有的单元格初始值设置为1
array.forEach((val, i) => {
if (val.label === value.label && i!== index && !this.spanIndex.includes(i)) {
this.spanIndex.push(index); //若有重复的将index放入spanIndex数组中
this.span[index]++; // 记录重复也就是单元格要合并的数量
}
})
})
this.span.map((value, index, array) => {
if (value > 1 ) {
// 将得到的单元格合并数据进行处理,让首个重复单元格保持不变,其余均变成
// 与首个重复单元格的距离,用负数表示容易区分。
for (let i = index + 1; i < index + value; i++) {
array[i] = index - i;
}
}
})
}
这是数据的初始化处理,使用vue时放在created钩子上。
headerStyle({ row, column, rowIndex, columnIndex }) {
// 若没有要合并的表头就直接返回
if (this.spanIndex.length < 1 )
return;
this.span.map((value, index, array) => {
// 判断条件为 该表头为首个重复项,则隐藏
if (value>1 || array[index+1] <1) {
row[index].colSpan = 0 // 本列表头隐藏
// 若为最后一个重复项
else if (value < 1) {
if (array[index + 1] === 1 || index >= array.length - 1){
row[index].colSpan = array[index + value] //最后一列表头扩展
}
})
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
// 若没有要合并的单元格,直接返回
if (this.spanIndex.length < 1 )
return;
// 当本列数据大于1时,说明是首个单元格
if (this.span[columnIndex] > 1 ) {
// 本列数据为空则收缩
if (['', null, undefined].includes(row[this.columnDef[columnIndex].prop])) {
return {
rowspan: 0, // 列扩展
colspan: 0 // 行扩展
}
} else {
// 本列数据不为空就展开,展开行数为重复但单元格数量
return {
rowspan: 1, // 列扩展
colspan: this.span[columnIndex] // 行扩展
}
}
// 当本列数据小于1时,说明是次单元格
} else if (this.span[columnIndex] < 1) {
for (let i =columnIndex - 1; this.span[i] !== 1; i-- ) {
// 从上一个数据开始判断,之前数据是否有为空的情况
if ( i >= 0 && row[this.columnDef[i].prop]){ // 只要有不为空,就收缩
return {
rowspan: 0, // 列扩展
colspan: 0 // 行扩展
}
}
// 说明之前的数据全为空或者首个单元格开始重复
if (i < 0 || this.span[ i - 1 ] === 1 ) {
// 本单元格不为空则扩展
if ((row[this.columnDef[columnIndex].prop])) {
return {
rowspan: 1, // 列扩展
colspan: i < 0 ? this.span[i + 1] :this.span[i] // 行扩展
}
// 本单元格为空则判断是否为最后一个重复单元格: 是就扩展,不是就收缩
} else if (this.span[columnIndex + 1 ] === 1 ) {
return {
rowspan: 1, // 列扩展
colspan: i < 0 ? this.span[i + 1] :this.span[i] // 行扩展
}
} else {
return {
rowspan: 0, // 列扩展
colspan: 0 // 行扩展
}
}
}
}
}
},
上面两个使用单元格扩展属性来操纵表格展示,更好的方法应该是用数组对象来操纵表格展示,这里只对这两天的内容做一个总结和记录,不推荐使用,下面是整个vue组件页面代码:
<template>
<div class="app">
<!--工具栏-->
<div class="head">
</div>
<!--表格渲染-->
<div class="body">
<el-row :gutter="15">
<el-col>
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span class="role-span">模版列表</span>
</div>
<el-table
ref="table"
:data="list"
:span-method="arraySpanMethod"
style="width: 100%;"
border
:header-cell-style="headerStyle"
>
<template v-for="column in columnDef">
<el-table-column
:key="column.prop"
:prop="column.prop"
:label="column.label"
align="center"
fixed
>
<template slot-scope="scope">
<span >
<span>{{ scope.row[scope.column.property] }} </span>
</span>
</template>
</el-table-column>
</template>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
export default {
name: "templateData",
data() {
return {
list: [
{'name': '李磊', 'sex':'男', 'age': '17', 'school': '洛阳理工' , 'Professional':'数学与应用数学' },
{'name': '张成', 'sex':'女', 'age': '18', 'school': '桂林电子科技', 'Professional':'应用化学' },
{'name': '练心', 'sex':'女', 'age': '22', 'school': '江西电子科技', 'Professional':'机械设计制造及其自动化' },
{'name': '余玠', 'sex':'男', 'age': '22', 'school': '华南理工', 'Professional':'理论与应用力学' }
],
columnDef: [
{ label: '姓名', prop: 'name' },
{ label: '性别', prop: 'sex' },
{ label: '年龄', prop: 'age' },
{ label: '学校', prop: 'school' },
{ label: '专业', prop: 'Professional' },
],
spanIndex: [],
span: []
};
},
created() {
this.columnSpanMethod();
},
methods: {
show(data) {
console.log(data)
},
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
if (this.spanIndex.length < 1 )
return;
if (this.span[columnIndex] > 1 ) {
if (['', null, undefined].includes(row[this.columnDef[columnIndex].prop])) {
return {
rowspan: 0, // 列扩展
colspan: 0 // 行扩展
}
} else {
return {
rowspan: 1, // 列扩展
colspan: this.span[columnIndex] // 行扩展
}
}
} else if (this.span[columnIndex] < 1) {
for (let i =columnIndex - 1; this.span[i] !== 1; i-- ) {
// debugger
if ( i >= 0 && row[this.columnDef[i].prop]){ // 不为空
return {
rowspan: 0, // 列扩展
colspan: 0 // 行扩展
}
}
if (i < 0 || this.span[ i - 1 ] === 1 ) { // 说明之前的数据全为空
if ((row[this.columnDef[columnIndex].prop])) {
return {
rowspan: 1, // 列扩展
colspan: i < 0 ? this.span[i + 1] :this.span[i] // 行扩展
}
} else if (this.span[columnIndex + 1 ] === 1 ) {
return {
rowspan: 1, // 列扩展
colspan: i < 0 ? this.span[i + 1] :this.span[i] // 行扩展
}
} else {
return {
rowspan: 0, // 列扩展
colspan: 0 // 行扩展
}
}
}
}
}
},
headerStyle({ row, column, rowIndex, columnIndex }) {
if (this.spanIndex.length < 1 )
return;
this.span.map((value, index, array) => {
if (value>1 || array[index+1] <1) {
row[index].colSpan = 0 // 本列表头隐藏
} else if (value < 1) {
if (array[index + 1] === 1 || index >= array.length - 1){
row[index].colSpan = array[index + value] //最后一列表头扩展
}
}
if (this.spanIndex.includes(columnIndex)) {
return 'display: none';
}
},
unique(arr) {
return Array.from(new Set(arr))
},
columnSpanMethod() {
this.span = [...this.columnDef];
this.columnDef.map((value, index, array) =>{
this.span[index] = 1;
array.forEach((val, i) => {
if (val.label === value.label && i!== index && !this.spanIndex.includes(i)) {
this.spanIndex.push(index);
this.span[index]++;
}
})
})
this.span.map((value, index, array) => {
if (value > 1 ) {
for (let i = index + 1; i < index + value; i++) {
array[i] = index - i;
}
}
})
}
}
};
</script>
<style lang="scss" scoped>
</style>