Vue2 + ElementUI -- el-table 的 SimpleTable 封装 变种(自适应高度 - 固定高度篇 - 全灵活)

248 阅读2分钟

专栏

效果

iShot_2024-12-06_14.27.13.gif

解决的问题

  • UI 要求底部分页跟随表格高度,达到内容区的最大高度时,采用滚动展示数据

思路

  • 不让使用固定高度,高度应是动态的
  • 考虑 resize 的情况,resize 后要重新计算高度问题

实现

  • 让父级 dom 先固定高度(伪的)

  • 需要已知 table 中的 表头高度 和 行高,通过数据长度得到表格的高度,同时和外层dom的高度做比较,如果超出则滚动

  • 此区域是 flex: 1; 实现的自适应区域,高度可变,当变化时要触发重新计算,为了提高性能,减少计算次数,所以采用了 element-resize-detector 监听外层 dom 的 窗口变化,当外层的dom尺寸变化的时候触发el-tableheight重新计算。

  • 安装插件 element-resize-detector 地址

npm install element-resize-detector -S
<div class="table-content" ref="myTableRef">
  <CustomTable
    :height="tableHeight"
    :columns="columns"
    :data="tableData"
    :isLoading="loading"
  >
    <template #warn="{scope}">
      <div
        :class="scope.row.is_warn === 1 ? 'warning-text' : 'normal-text'"
      >
        {{ scope.row.is_warn === 1 ? '是' : '否' }}
      </div>
    </template>
  </CustomTable>
  <el-pagination
    class="custom-pagination"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
    :current-page.sync="pageData.pageNum"
    :page-size="pageData.pageSize"
    layout="total, prev, pager, next"
    :total="pageData.total"
    background
  />
</div>
import elementResizeDetectorMaker from 'element-resize-detector';

export default {
    data: () => ({
        erd: elementResizeDetectorMaker(),
        tableMaxHeight: null,
        pageData: {
          pageNum: 1,
          pageSize: 10,
          total: 0,
        },
        tableData: [],
        columns: [],
        loading: false,
        tableHeaderHeight: 60, // 表格 header 高度
        tableRowHeight: 60, // 表格的行高
        paginationHeight: 50, // 分页的高度
    }),
    computed: {
        tableHeight() {
          if (this.tableMaxHeight == null) {
            return null;
          }
          const len = this.tableData.length;
          return (len * this.tableRowHeight + this.tableHeaderHeight) > this.tableMaxHeight ? this.tableMaxHeight : null;
        },
    },
    mounted() {
        // 获取 外层 dom 高度
        this.onResize()
    },
    methods: {
        getTableData() {
        },
        onResize() {
          this.erd.listenTo(this.$refs.myTableRef, (ele) => {
            this.tableMaxHeight = ele.offsetHeight - this.paginationHeight;
            console.log('<<<<<first>>>>>', this.tableMaxHeight);
          });
        },
        handleSizeChange(val) {
          this.pageData.pageSize = val;
          this.getTableData();
        },
        handleCurrentChange(val) {
          this.pageData.pageNum = val;
          this.getTableData();
        },
    }
}

// 父级 纵向 flex
display: flex;
flex-direction: column;
...

.table-content {
    position: relative;
    flex: 1; // 自动分配剩余部分
    overflow: hidden;
    
    // 分页布局 调整
    .custom-pagination {
      margin-top: 15px;
      display: flex;
      justify-content: flex-end;
      position: relative;
      /deep/ .el-pagination__total {
        position: absolute;
        left: 0;
      }
    }
}