vue+elementui实现动态多级表头+合并单元格+自适应列宽
程序员文章站
2022-06-08 15:45:06
...
1.动态多级表头的实现
因为项目需求是要根据不同查询条件,显示不同的表头,所以需要动态渲染表头
在表格渲染的时候,label和prop要对应起来,简单一点的办法就是让后端传过来,这是我给后端提供的格式
title:[
{label:'一级标题1',item:[ //label为表头的内容,prop为对应的字段名(注意字段名要和后端传过来的数据列表的字段名一致)
{label:'二级标题1',item:[
{label:'三级标题1',prop:'value1'},
{label:'三级标题2',prop:'value2'},
{label:'三级标题3',prop:'value3'},
{label:'三级标题4',prop:'value4'},
{label:'三级标题5',prop:'value5'},
]},
{label:'二级标题1',prop:'value6'},
{label:'二级标题2',prop:'value7'},
{label:'二级标题3',prop:'value8'},
{label:'二级标题4',prop:'value9'},
{label:'二级标题5',prop:'value10'},
]},
{label:'一级标题2',prop:'value11'},
],
接收到后端传过来的title列表后,在template中渲染
ps:我的表头嵌套最多三层,所以直接这样写了,需要无限嵌套表头的童鞋自行百度吧有很多
<el-table
:data="tableData">
<el-table-column v-for="(v,idx) in tableHeader" :key="idx" //tableHeader为后端传过来的title列表
:label="v.label" :prop="v.prop" :width="v.width" align="center">
<el-table-column
v-for= "(j,i) in v.item"
:key="i"
:prop="j.prop"
:label="j.label"
:width="j.width" align="center">
<el-table-column
v-for= "(m,n) in j.item"
:key="n"
:prop="m.prop"
:label="m.label"
:width="m.width" align="center">
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
2.合并单元格
因为表格中的数据可能相邻几行中的前几列内容是一样的,所以需要合并行
<el-table
:data="tableData"
:span-method="arraySpanMethod"> //添加此方法
<el-table-column v-for="(v,idx) in tableHeader" :key="idx"
:label="v.label" :prop="v.prop" :width="v.width" align="center">
<el-table-column
v-for= "(j,i) in v.item"
:key="i"
:prop="j.prop"
:label="j.label"
:width="j.width" align="center">
<el-table-column
v-for= "(m,n) in j.item"
:key="n"
:prop="m.prop"
:label="m.label"
:width="m.width" align="center">
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
export default {
data() {
return {
tableData :[],
spanArr:[], //需要合并行的个数
position:0
}
}
}
//获取列表数据
getList(page) {
this.$axios.post('------URL-----').then(res => {
this.tableData = res.data.data.data; //接收列表数据
this.rowspan(); //计算需要合并的行的个数
});
},
//获得数据相同的行数
rowspan() {
//每次调用清空数据
this.spanArr=[];
this.position=0
this.tableData.forEach((item,index) => {
if( index === 0){
this.spanArr.push(1);
this.position = 0;
}else{
if(this.tableData[index].id === this.tableData[index-1].id ){
this.spanArr[this.position] += 1;
this.spanArr.push(0);
}else{
this.spanArr.push(1);
this.position = index;
}
}
})
},
//合并单元格
arraySpanMethod({ row, column, rowIndex, columnIndex }) { //表格合并行
if (columnIndex <= 9 ) { //我项目中需要前9项的行合并
const _row = this.spanArr[rowIndex] ; //需要合并多少行
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col
}
}
},
3.自适应列宽
百度所知elementui是暂不支持根据内容自适应列宽的,fit属性并没有用
export default {
data() {
return {
tableData :[],
titleList:[], //调用接口接收到的title列表
tableHeader:[], //渲染的列表,已经加上width属性
}
}
},
methods:{
//获取列表数据
getList(page) {
this.$axios.post('------URL-----').then(res => {
this.tableData = res.data.data.data; //接收列表数据
this.titleList = res.data.data.title; //接收列表数据
this.tableHeader = this.getAllItem(this.titleList,this.tableData) //参数:title列表 数据列表
});
},
//获取每列数据,通过计算加上width属性
getAllItem(head,data){
const _this = this
head.forEach(item => {
if(item.item){ //递归,判断是否为最后一级标题
_this.getAllItem(item.item,data)
}else {
const arr = data.map(x => x[item.value]) // 获取每一列的所有数据
arr.push(item.label) // 把每列的表头也加进去算
item.width = _this.getMaxLength(arr) + 50 // 每列内容最大的宽度 + 表格的内间距
return item
}
})
return head
},
//使用span标签包裹内容,然后计算span的宽度 width: px
getTextWidth(str) {
let width = 0;
let html = document.createElement('span');
html.innerText = str;
html.className = 'getTextWidth';
document.querySelector('body').appendChild(html);
width = document.querySelector('.getTextWidth').offsetWidth;
document.querySelector('.getTextWidth').remove();
return width;
},
}
4.固定表格底部横向滚动条
因为内容过多,当想看表格最后几项内容时,需要把右侧滚动条滑到底部才能看到横向滚动条
<el-table
:data="tableData"
:height="table_height" //给表格添加该属性
:span-method="arraySpanMethod">
</el-table>
mounted() { //在mounted中获取窗口的高,动态计算表格的高
const that = this;
that.table_height=document.body.clientHeight-280 //该处减去了头部底部的高度,可按自己需求修改
window.onresize = function() {
that.table_height=document.body.clientHeight-280
};
},
总体代码
<template>
<el-table
:data="tableData"
:span-method="arraySpanMethod">
<el-table-column v-for="(v,idx) in tableHeader" :key="idx"
:label="v.label" :prop="v.prop" :width="v.width" align="center">
<el-table-column
v-for= "(j,i) in v.item"
:key="i"
:prop="j.prop"
:label="j.label"
:width="j.width" align="center">
<el-table-column
v-for= "(m,n) in j.item"
:key="n"
:prop="m.prop"
:label="m.label"
:width="m.width" align="center">
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
</template>
export default {
data() {
return {
tableData :[],
titleList:[], //调用接口接收到的title列表
tableHeader:[], //渲染的列表,已经加上width属性
spanArr:[],
position:0,
}
}
},
mounted() { //在mounted中获取窗口的高,动态计算表格的高
const that = this;
that.table_height=document.body.clientHeight-280 //该处减去了头部底部的高度,可按自己需求修改
window.onresize = function() {
that.table_height=document.body.clientHeight-280
};
},
methods:{
//获取列表数据
getList(page) {
this.$axios.post('------URL-----').then(res => {
this.tableData = res.data.data.data; //接收列表数据
this.titleList = res.data.data.title; //接收列表数据
this.tableHeader = this.getAllItem(this.titleList,this.tableData) //参数:title列表 数据列表
this.rowspan()
});
},
//获得数据相同的行数
rowspan() {
//每次调用清空数据
this.spanArr=[];
this.position=0
this.tableData.forEach((item,index) => {
if( index === 0){
this.spanArr.push(1);
this.position = 0;
}else{
if(this.tableData[index].id === this.tableData[index-1].id ){
this.spanArr[this.position] += 1;
this.spanArr.push(0);
}else{
this.spanArr.push(1);
this.position = index;
}
}
})
},
//合并单元格
arraySpanMethod({ row, column, rowIndex, columnIndex }) { //表格合并行
if (columnIndex <= 9 ) { //我项目中需要前9项的行合并
const _row = this.spanArr[rowIndex] ; //需要合并多少行
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col
}
}
},
//获取每列数据,通过计算加上width属性
getAllItem(head,data){
const _this = this
head.forEach(item => {
if(item.item){ //递归,判断是否为最后一级标题
_this.getAllItem(item.item,data)
}else {
const arr = data.map(x => x[item.value]) // 获取每一列的所有数据
arr.push(item.label) // 把每列的表头也加进去算
item.width = _this.getMaxLength(arr) + 50 // 每列内容最大的宽度 + 表格的内间距
return item
}
})
return head
},
//使用span标签包裹内容,然后计算span的宽度 width: px
getTextWidth(str) {
let width = 0;
let html = document.createElement('span');
html.innerText = str;
html.className = 'getTextWidth';
document.querySelector('body').appendChild(html);
width = document.querySelector('.getTextWidth').offsetWidth;
document.querySelector('.getTextWidth').remove();
return width;
},
}
上一篇: day25 类的封装和类的绑定方法