美文网首页
通过继承实现el-table-column列宽根据内容自适应

通过继承实现el-table-column列宽根据内容自适应

作者: 黎杰_Lj | 来源:发表于2020-03-10 20:49 被阅读0次

    安装

    已封装到npm, 可直接安装使用:

    $ npm install ex-table-column --save
    
    $ yarn add ex-table-column
    

    github地址:
    https://github.com/mnm1001/ex-table-column

    需求

    项目中使用element-uiel-tableel-table-column,
    需求上需要实现列宽根据内容自适应.

    实现方案

    element-ui 的table组件本身有着强大的功能, 所以我们期望保留其现有功能, 然后进行扩展. 基于这样的前提, 继承el-table-column组件进行扩展是一个比较合适的方案.

    Vue组件继承

    vue 提供 extends 以扩展已有组件, 所以我们很容易实现一个扩展于 el-table-column 的组件 ex-table-column:

    import { TableColumn } from 'element-ui';
    
    export default {
      name: 'ExTableColumn',
      extends: TableColumn, // 指定继承组件
    };
    

    介入el-table-columnwidth计算

    element-uitable-column.js 源码中, 我们发现以下一些内容和width计算有关.

      computed: {
        realWidth() {
          return parseWidth(this.width);
        },
    
        realMinWidth() {
          return parseMinWidth(this.minWidth);
        },
      },
      methods: {
        setColumnWidth(column) {
          if (this.realWidth) {
            column.width = this.realWidth;
          }
          if (this.realMinWidth) {
            column.minWidth = this.realMinWidth;
          }
          if (!column.minWidth) {
            column.minWidth = 80;
          }
          column.realWidth = column.width === undefined ? column.minWidth : column.width;
          return column;
        },
      },
      created() {
        const chains = compose(this.setColumnRenders, this.setColumnWidth, this.setColumnForcedProps);
        column = chains(column);
    
        this.columnConfig = column;
      },
    

    我们的实现思路是Table先渲染, 计算当列内容的宽度中的最大值, 再将最大值赋予列宽然后刷新. 所以:

    • 无法在created中介入, 因为此时Table还没有mouted,
    • 若在methods中介入的话, 我们还需要手动刷新一次组件以触发新的width, 也不合适,
    • 所以修改computed是相对合适的, 因为computed所依赖的值发生变化以后会自动触发组件的更新.

    计算内容宽度并更新列宽

    Table组件mounted后遍历当列内容, 获取最大值. 然后将此值存入dataautoWidth中, 并使autoWidth介入到realMinWidthcomputed计算中, 这样就简单的实现了自动列宽的功能.

      data() {
        return {
          autoWidth: 0,
        };
      },
      computed: {
        realMinWidth() {
          return this.autoWidth;
        },
      },
      mounted() {
        let cells = window.document.querySelectorAll(`td.${this.columnId} .cell`);
        const autoMinWidth = max(map(cells, item => item.getBoundingClientRect().width));
        this.autoWidth = autoMinWidth;
      },
    

    完善

    至此我们已基本实现自动列宽功能, 然而还有一些问题需要完善:

    兼容

    我们其实期望不去改变el-table-column的原有特性, 而这里直接覆盖realMinWidth的值稍显粗暴, 所以我们可以通过传入一个名为autoFixprop来决定是否启用自动内容列宽功能, 若autoFixfalse, 则保留el-table-column原有的realMinWidth计算逻辑:

    props: {
        autoFit: {
          type: Boolean,
          default: false,
        },
      },
      data() {
        return {
          autoWidth: 0,
        };
      },
      computed: {
        realMinWidth() {
          if (this.autoFit) {
            return parseMinWidth(max([this.minWidth, this.autoWidth]));
          }
          return parseMinWidth(this.minWidth);
        },
      },
    
    灵活性

    el-table-column有复杂的solt内容, 我们可能期望指定某一个element来计算列宽, 所以可以传入一个fitByClass的属性来指定计算列宽所依赖的element:

      props: {
        fitByClass: {
          type: String,
          default: 'cell',
        },
      },
      mounted() {
        let cells = window.document.querySelectorAll(`td.${this.columnId} .${this.fitByClass}`);
        if (isEmpty(cells)) {
          cells = window.document.querySelectorAll(`td.${this.columnId} .cell`);
        }
        const autoMinWidth = max(map(cells, item => item.getBoundingClientRect().width));
        this.autoWidth = autoMinWidth;
      },
    
    分页更新

    当Table带有分页时, 切换分页不会重新触发mounted, 但Table的列内容的最大宽度可能需要重新计算, 所以需要在updated中重新计算autoWidth:

      methods: {
        updateAutoWidth() {
          let cells = window.document.querySelectorAll(`td.${this.columnId} .${this.fitByClass}`);
          if (isEmpty(cells)) {
            cells = window.document.querySelectorAll(`td.${this.columnId} .cell`);
          }
    
          const autoMinWidth = max(map(cells, item => item.getBoundingClientRect().width));
          if (this.autoWidth !== autoMinWidth) {
            this.autoWidth = autoMinWidth;
          }
        },
      },
      updated() {
        this.updateAutoWidth();
      },
      mounted() {
        this.updateAutoWidth
      },
    

    最后

    中间代码有所精简, 完整源码可以参考 ExTableColumn.js .
    已封装到npm, 可通过npm install ex-table-column --save安装使用.

    相关文章

      网友评论

          本文标题:通过继承实现el-table-column列宽根据内容自适应

          本文链接:https://www.haomeiwen.com/subject/xntwdhtx.html