ElTable设置max-height滚动失效问题

4,646 阅读2分钟

前言

最近写vue的项目,接触到了一个问题,就是el-table中的max-height只在设置为px时滚动才生效,而为100%时滚动未生效,而height属性设置为100%则正常,因此阅读了下el-table的源码,解决了下这个问题。

max-height不滚动原因

我们先来看下dom结构是怎样的。

先将max-height设置为固定px值250px,可以看到el-table__body-wrapper盒子设置了一个max-height,下级的table为自个的高度,那在这种情况下滚动正常。 5b6j8-znuug.gif

max-height设置为100%后,可以看到el-table__body-wrapper盒子的max-height属性未设置,变成了下级table的高度,滚动失效。 image.png

阅读源码,可以找到el-table__body-wrapper的style样式来自bodyHeight image.png

    bodyHeight() {
        const { headerHeight = 0, bodyHeight, footerHeight = 0} = this.layout;
        if (this.height) {
          return {
            height: bodyHeight ? bodyHeight + 'px' : ''
          };
        } else if (this.maxHeight) {
          const maxHeight = parseHeight(this.maxHeight);
          if (typeof maxHeight === 'number') {
            return {
              'max-height': (maxHeight - footerHeight - (this.showHeader ? headerHeight : 0)) + 'px'
            };
          }
        }
        return {};
      }
   // parseHeight 
   function parseHeight(height) {
      if (typeof height === 'number') {
        return height;
      }
      if (typeof height === 'string') {
        if (/^\d+(?:px)?$/.test(height)) {
          return parseInt(height, 10);
        } else {
          return height;
        }
      }
      return null;
   }
      

源码中可以看到parseHeight函数,当传入值为字符串时会正则匹配/^\d+(?:px)?$/,那当我们传入的为100%时,这边就匹配不到,啥也没返回,因此就有了上面的可以看到的现象el-table__body-wrapper盒子的max-height属性未设置,自然就不会有滚动效果了。

解决方案

知道了原因,那来解决下这个问题。

可以看到问题出在了bodyHeight,那我们要做的就是重写bodyHeight这个计算方法,这边可以用到vue的extends方法。创建一个MyTable.vue文件,先继承el-table

import { Table } from "element-ui";
export default {
  extends: Table,
};

我们对bodyHeight函数进行改造,当maxHeight字段正则匹配为百分比时,进行calc重新计算max-height的高度

import { Table } from "element-ui";
import { parseHeight } from "element-ui/packages/table/src/util.js";
export default {
  extends: Table,
  computed: {
    bodyHeight() {
      const { headerHeight = 0, bodyHeight, footerHeight = 0 } = this.layout;
      if (this.height) {
        return {
          height: bodyHeight ? bodyHeight + "px" : "",
        };
      } else if (this.maxHeight) {
        const maxHeight = parseHeight(this.maxHeight);
        if (typeof maxHeight === "number") {
          return {
            "max-height":
              maxHeight -
              footerHeight -
              (this.showHeader ? headerHeight : 0) +
              "px",
          };
        } else if (maxHeight.match(/\d+%/g)) {
          return {
            "max-height": `calc(${maxHeight} - ${
              footerHeight + this.showHeader ? headerHeight : 0
            }px)`,
          };
        }
      }
      return {};
    },
  },
};

查看效果时,el-table__body-wrapper盒子有了max-height属性,可滚动还是没有出现,分析dom结构,可以看到问题就出在父盒子el-table的高度也为max-height:100%,因此子盒子的max-height:100%并不会起作用。 image.png

解决办法可以通过flex来解决,给父盒子添加display:flex; image.png 滚动条出现,但布局乱了,我们再解决下布局问题就可以了。

给表头el-table__header-wrapper盒子添加flex-shrink: 0;,表格el-table__body-wrapper盒子添加flex-grow: 1; image.png 滚动条出现,问题解决。

最终重写的MyTable代码:

<script>
import { Table } from "element-ui";
import { parseHeight } from "element-ui/packages/table/src/util.js";
export default {
  extends: Table,
  computed: {
    bodyHeight() {
      const { headerHeight = 0, bodyHeight, footerHeight = 0 } = this.layout;
      if (this.height) {
        return {
          height: bodyHeight ? bodyHeight + "px" : "",
        };
      } else if (this.maxHeight) {
        const maxHeight = parseHeight(this.maxHeight);
        if (typeof maxHeight === "number") {
          return {
            "max-height":
              maxHeight -
              footerHeight -
              (this.showHeader ? headerHeight : 0) +
              "px",
          };
        } else if (maxHeight.match(/\d+%/g)) {
          return {
            "max-height": `calc(${maxHeight} - ${
              footerHeight + this.showHeader ? headerHeight : 0
            }px)`,
          };
        }
      }
      return {};
    },
  },
};
</script>
<style scoped>
.el-table {
  display: flex;
  flex-direction: column;
}
.el-table >>> .el-table__header-wrapper {
  flex-shrink: 0;
}
.el-table >>> .el-table__body-wrapper {
  flex-grow: 1;
}
</style>
// 调用
<my-table :data="tableData" max-height="100%" border style="width: 100%">
    <el-table-column prop="date" label="日期" width="180">
    </el-table-column>
    <el-table-column prop="name" label="姓名" width="180">
    </el-table-column>
    <el-table-column prop="address" label="地址"> </el-table-column>
 </my-table>