项目上有一个需求,需要用el-table来显示数据,有一个要求就是不能换行。表头不能换行,表格里面的内容也不能换行。
同事写的页面使用的是vue3,自定义了一个事件来动态变化每一列的参数。我将其挪用到vue2中完全没法使用。只能在网上查找资料来实现它。
表格通过接口来获取,接口中将表头标题和表格内容分开来的。
基本思路就是:表格内容限制不换行,不使用缩略符号。
首先从表头开始,在el-table-column中有一个render-header
// 表头部重新渲染
renderHeader(h, { column, $index }) {
// 新建一个 span
let span = document.createElement('span');
// 设置表头名称
span.innerText = column.label;
// 临时插入 document
document.body.appendChild(span);
// 重点:获取 span 最小宽度,设置当前列,注意这里加了 20,字段较多时还是有挤压,且渲染后的 div 内左右 padding 都是 10,所以 +20 。(可能还有边距/边框等值,需要根据实际情况加上)
column.minWidth = (span.getBoundingClientRect().width) + 40;
this.headerLableWidth[column.property] = column.minWidth;
// 移除 document 中临时的 span
document.body.removeChild(span);
return h('span', column.label);
},
column中有这些标题文字信息, 创建一个span标签,添加到文档流中,然后拿到它的宽度,为了多加点宽度,可以额外多加些数值。代码中多加了40宽度。为表头设置最小宽度。
记录这一列的最小宽度,当表格内容动态设置宽度的时候,至少要给定成表头的宽度。不然表头会因为没有内容宽度变成0.
flexColumnWidth(str, arr1, flag = 'max'){
// str为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
// flag为可选值,可不传该参数,传参时可选'max'或'equal',默认为'max'
// flag为'max'则设置列宽适配该列中最长的内容,flag为'equal'则设置列宽适配该列中第一行内容的长度。
str = str + ''
let columnContent = ''
if (!arr1 || !arr1.length || arr1.length === 0 || arr1 === undefined) {
return
}
if (!str || !str.length || str.length === 0 || str === undefined) {
return
}
if (flag === 'equal') {
// 获取该列中第一个不为空的数据(内容)
for (let i = 0; i < arr1.length; i++) {
if (arr1[i][str].length > 0) {
// console.log('该列数据[0]:', arr1[0][str])
columnContent = arr1[i][str]
break
}
}
} else {
// 获取该列中最长的数据(内容)
let index = 0
for (let i = 0; i < arr1.length; i++) {
if (arr1[i][str] === null) {
return
}
const now_temp = arr1[i][str] + ''
const max_temp = arr1[index][str] + ''
if (now_temp.length > max_temp.length) {
index = i
}
}
columnContent = arr1[index][str]
}
// console.log('该列数据[i]:', columnContent)
// 以下分配的单位长度可根据实际需求进行调整
let flexWidth = 0
for (const char of String(columnContent)) {
if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
// 如果是英文字符,为字符分配8个单位宽度
flexWidth += 10
} else if (char >= '\u4e00' && char <= '\u9fa5') {
// 如果是中文字符,为字符分配15个单位宽度
flexWidth += 18
} else {
// 其他种类字符,为字符分配8个单位宽度
flexWidth += 10
}
}
if (flexWidth < this.headerLableWidth[str]) {
// 设置最小宽度
flexWidth = this.headerLableWidth[str]
}
// if (flexWidth > 250) {
// // 设置最大宽度
// flexWidth = 250
// }
// console.log(flexWidth)
return flexWidth + 'px'
}
}
el-table-column标签中的width使用函数方法来代替。
完整的el-table如下
<el-table
:ref='tableRef'
:data="certRecordInfos"
border
:fit="true"
style="width: 100%">
<el-table-column
align="center"
:render-header="renderHeader"
:width="flexColumnWidth(item.key,certRecordInfos)"
:key="item.key"
:prop="item.key"
:label="item.value" >
</el-table-column>
</el-table>
因为需要先获取到表头的最小宽度,因此需要先加载表头,才能确保后面加载表格内容的时候,能正确的设置宽度。
在watch中,观察这两个数组,当发现变化的时候,去重新刷新这个table
certHeaderList: {
deep: true,
handler: function (val) {
this.$nextTick(() => {
this.$refs[`${this.tableRef}`].doLayout();
})
}
},
certRecordInfos: {
deep: true,
handler: function (val) {
this.$nextTick(() => {
this.$refs[this.tableRef].doLayout();
})
}
}
this.certHeaderList.splice(0)
this.certRecordInfos.splice(0)
const resultHeader = val[0].header
resultHeader.forEach((header)=>{
let map = {key:header.columnName,value:header.columnDesc};
this.certHeaderList.push(map);
});
setTimeout(() => {
const resultList = val[0].list
this.certRecordInfos.push(...resultList)
}, 1000);
要实现效果,必须要确保已经拿到了表格每一列表头的最小宽度。并使用headerLableWidth记录下来。
另外,需要为表格内容进行设置,确保内容不会进行换行和使用缩略符号。
/deep/ .el-table th, .el-table td {
white-space: nowrap;
}
/deep/ .el-table .cell {
display: inline-block;
white-space: nowrap;
width: auto;
overflow: auto;
}
/deep/ .el-table .el-table__body-wrapper {
overflow-x: auto;
}