vue中大量数据表格的虚拟滚动(ant)

1,058 阅读1分钟

整体思路

//变量注释
tableData:保存所有数据
sliceTable:保存当前表格展示的数据
startIndex: 数据截取的开始下标
rowHeight: 行高度
  1. 页面中a-table设置scroll={y:600}。(一定要设置,不然表格不会出现滚动条)、
  2. 在mounted中使用给表格父容器绑定滚动事件
  3. 获取到你所要展示的所有数据,我这边的需求是一次返回所有数据,大概有3000多条
  4. 在滚动事件中获取滚动元素的scrollTop,根据scrollTop/行高度,计算出数据截取的开始下标(startIndex)
  5. 对table进行滚动操作,transform = translate3D(0,${this.startIndex * rowHeight}px,0)
  6. 使用computed创建sliceTable,。根据startIndex的改变,截取tableData的数据,展示出不同的数据

表格的页面代码

<a-table
      ref="tableRef"
      size="middle"
      :rowKey="r => Math.random()+''"
      :rowClassName="setRowClassName"
      :data-source="sliceTable"
      :pagination="false"
      :scroll="{x: 'max-content', y: 600}"
      :columns="columns"
      :loading="loading"
    >
    </a-table>

js中的代码

sliceTable变量 第一次截取出的sliceTable的长度必须让表格出现滚动条,否则就无法触发scroll事件,就无法进行向下滚动加载后面的数据

sliceTable() {
    //每次展示20条数据,可以自己定义
      return this.tableData.slice(this.startIndex, this.startIndex + 20);
    },

绑定滚动事件

this.$refs.tableRef.$el
    .querySelector(".ant-table-body") //找到包含表格的父容器
    .addEventListener("scroll", this.tableScroll, {
      passive: true
    });

滚动事件

   tableScroll() {
       //行高度
      const rowHeight = 27
      const bodyWrapperEle = this.$refs.tableRef.$el.querySelector(".ant-table-body");
      //如果有列固定,ant会使用另外一个表格
      const fixedWrapperEle = this.$refs.tableRef.$el.querySelector(".ant-table-fixed-left")
      // 滚动的高度
      const scrollTop = bodyWrapperEle.scrollTop;
      // 下一次开始的索引
      this.startIndex = Math.floor(scrollTop/rowHeight);
      //滚动操作
      bodyWrapperEle.querySelector(".ant-table-tbody").style.transform = `translate3D(0,${this.startIndex * rowHeight}px,0)`;
      if(fixedWrapperEle) {
        fixedWrapperEle.querySelector('.ant-table-tbody').style.transform = `translate3D(0,${this.startIndex * rowHeight}px,0)`;
      }
      
      // 滚动到底,加载新数据
      if (bodyWrapperEle.scrollHeight <= scrollTop + bodyWrapperEle.clientHeight) {
        if (this.tableData.length == this.total) {
          this.$message.warning("没有更多了");
          return;
        }
      }
    }

获取所有数据

    getList() {
      this.loading = true
      shopProfitList({ //你自己的接口
        ...this.queryParams,
        dataDimension: this.tabIndex
      }).then(res => {
        if(res.code == 0) {
          //重新加载数据时清空之前所有数据的操作
          this.startIndex = 0
          //使得滚动条滚动到顶部
          this.$refs.tableRef.$el.querySelector(".ant-table-body").scrollTop = 0
          this.total = res.data.length
          this.loading = false
        }
      })
    },