项目上有一个需求,需要用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;
}

发表回复