先看效果
列设置
表格双表头固定列、列展示不折行
背景
- 表格需求如下:
-
双表头、字段个数不确定、可由另一个模块动态新增,另外产品希望字段一行展示不要有折行也不要省略展示,由于基础字段就有一百多个、所以需要列设置管理展示的字段、需要固定列。故产生以下问题点
1.1 不确定字段个数所以只能采取动态双表头形式、字段全部由后端返回 1.2 字段一行展示、一般我们都通过挨个设置width来调整、但是字段这么多、还可以动态新增进来根本无法确定所需的字段的宽度,故该挨个设置的方案不行、只能通过动态计算列的宽度 1.3 用列设置管理列展示后、上面的计算列就会产生内容没有占满整个表格宽度的问题,我们希望总列宽小于表格宽度的时候能自动撑开、超过的时候才去计算列宽。
不计算列宽的话就会产生折行
1.4 element-ui 目前只支持单表头固定列、查询了下网上的解决方案、大致如下
1、通过给第一级的表头设置一个固定宽度、然后第二级的宽度之和等于第一级比表头设置的宽度。经研究该方法对于固定列的表格可行、但是我们的需求可以进行列设置、列宽不定、无法直接使用,但是能参考解决思路
2、去改element-ui的源码让其支持双表头固定列、但是由于项目是多人合作、打包上线是走的自动化工具、不方便。
解决方案
1.1的问题,很好解决、双表头遍历就行了
1.2的问题我们需要动态的去计算每一个列的宽度、而每一列我们需要去比较标题和内容的宽取长的数据作为列宽
- flexWidth(c.code, tableData, c.label, 50)函数具体实现如下
const flexWidth = (prop, tableData, title, num = 0) => {
if (tableData?.length === 0) {
//表格没数据不做处理
return;
}
let flexWidth = 0; //初始化表格列宽
let columnContent = ''; //占位最宽的内容
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
context.font = '12px Microsoft YaHei';
if (prop === '' && title) {
//标题长内容少的,取标题的值,
columnContent = title;
} else {
// 获取该列中占位最宽的内容
let index = 0;
for (let i = 0; i < tableData.length; i++) {
const now_temp = tableData[i][prop] + '';
const max_temp = tableData[index][prop] + '';
const now_temp_w = context.measureText(now_temp).width;
const max_temp_w = context.measureText(max_temp).width;
if (now_temp_w > max_temp_w) {
index = i;
}
}
columnContent = tableData[index][prop];
//比较占位最宽的值跟标题、标题为空的留出四个位置
const column_w = context.measureText(columnContent).width;
const title_w = context.measureText(title).width;
if (column_w < title_w) {
columnContent = title || '留四个字';
}
}
// 计算最宽内容的列宽
let width = context.measureText(columnContent);
flexWidth = width.width + num;
return flexWidth + 'px';
1.3的问题 我们解决完列宽后还需要进一步去判断 当前的列宽总和是否大于表格可视区?
实现代码如下:
到了解决element双表头问题了
- 参考方案一的方案需要对第一级进行固定列并确定宽度,但是因为可以设置列的原因我们可以去第一个一级表头设置fixed属性,宽度我们可以通过动态的去计算所需要固定的列的宽度,目前我的需求是固定前四列,切这四列涉及到了两个表头、我的处理方法如下
computed: {
getTableHeader() {
return this.tableHeader.map((v, i) => {
if (i == 0) {
this.$set(v, 'fixed', 'left');
// 加这个给详情页默认固定前四列
this.$set(v, 'width', this.topFourTotalWidth);
}
return v;
});
}
}
watch: {
tableHeader: {
handler(val) {
this.completeCalc = false;
const tempTableHeader = JSON.parse(JSON.stringify(val));
this.tableHeaderList = treeToList(tempTableHeader);
this.$nextTick(() => {
setTimeout(() => {
let tableDom = this.$refs.table;
if (this.tableData.length) {
// 判断是否需要设置列宽
this.isSetColumnWidth = this.handleCompareWidth(this.tableHeaderList);
}
this.completeCalc = true;
this.$eventBus.$emit('setCompleteCalc', true);
setTimeout(() => {
// 固定前四列, 固定类的方法在这里你们看这里就可以了
this.setFixedField(tableDom, 4);
tableDom.doLayout();
}, 100);
}, 600);
});
},
deep: true,
immediate: true
}
},
methods: {
// 动态计算规定列宽度
setFixedField(tableDom, num) {
let topFourFieldList = tableDom.columns.filter((v, index) => index < num);
let topFourFieldWidthList = \[];
topFourFieldList.forEach((item) => {
topFourFieldWidthList.push(item.width);
});
this.topFourTotalWidth = this.flexWidthSum(topFourFieldWidthList);
const dom = Array.from(document.getElementsByClassName('el-table\_\_fixed'))\[0];
console.log('dom', dom);
dom.style.width = this.topFourTotalWidth + 'px';
}
}
另外一个不可忽略的重点就是把element的样式重置一下 不然文字会给固定的列遮挡住了
.el-table th.is-hidden > *,
.el-table td.is-hidden > * {
visibility: visible;
}
至此就完美解决啦,有疑问可以留言探讨哦!