antv表格大量数据卡顿问题(局部渲染数据)

  表格最大数据量也就500左右,再多,dom太多,浏览器会卡顿。为了解决这个问题,同时保持表格原有功能,对数据做了优化。

  特点:

  1、保留原有antv的table的所有功能(antd-react 一样的道理,这里只贴vue代码,react抄一下函数即可)

  2、数据切换流畅,无卡顿问题,头尾数据无空白问题

  3、可视区域渲染数据,条数默认15条,可配置,注意和可视高度配合

  4、写法很简单

 思路: 默认每条数据高度一样,不换行。增加一个滚动条,滚动滚动条,根据百分比,计算要展示的数据

 缺点:全选会触发2次数据的回调,这个暂时没处理;若表格换行,高度相差太大影响数据显示,需要配置合理的高度

 

 贴一下代码,有需要的自己拷贝:  ps:对分页的一些功能还没封装完,直接忽略,看核心部分即可

<template>
  <div class="c-large-table">
    <a-table
      clas
      :loading="loading"
      :columns="columns"
      :row-key="record => record.id"
      :data-source="tableData"
      :row-selection="selected ? { selectedRowKeys: selectedRowKeys, onChange: handleSelect, onSelectAll: handleSelectAll } : null"
      @change="handleTableChange"
      :pagination="pagination"
    >
      <template slot="name" slot-scope="name"> {{ name.first }} {{ name.last }} </template>
    </a-table>
<!-- 虚拟滚动条 -->
    <div class="sc" :style="{height: tableHeight+'px'}">
      <div class="scbc" :style="{height: totalHeight+'px'}"></div>
    </div>
  </div>
</template>

<script>
const ROWS = 15,          // 局部渲染的数据条数
      HEIGHT = 29.6,      // 每行的高度
      TABLEHEIGHT = 446;  // 表格可视高度

export default {
  props: {
    loading: {
      type: Boolean,
      default: false
    },
    dataSource: {
      type: Array,
      default: []
    },
    columns: {
      type: Array,
      default: []
    },
    pagination: {
      type: Object,
      default: {
        current: 1,
        pageSize: 20,
        tota: 0,
        showSizeChanger: true,
        showQuickJumper: true,
        pageSizeOptions: ["20", "50", "100", "200", "500", "1000", "2000"]
      }
    },
    rows: {   // 可视区域展示多少行
      type: Number,
      default: ROWS
    },
    rowHeight: { // 每行的高度
      type: Number,
      default: HEIGHT
    },
    tableHeight: { // 可是区域高度
      type: Number,
      default: TABLEHEIGHT
    },
    selected: { // 是否可选
      type: Boolean,
      default: false
    },
    selectChange: { // 可选的回调
      type: Function,
    },
  },
  data() {
    return {
      scrollEle: '',
      tableData: [],
      selectedRowKeys: [],
      totalHeight: 446,  // 数据总高度
      idx: 0,            // 当前开始下标
    };
  },
  watch: {
    dataSource () {
      const { dataSource, rows, rowHeight } = this
      this.tableData = dataSource.length > rows ? dataSource.slice(0, rows) : dataSource
      this.totalHeight = dataSource.length * rowHeight
    }
  },
  created() {
    const { dataSource, rows, rowHeight } = this
    this.tableData = dataSource.length > rows ? dataSource.slice(0, rows) : dataSource
    this.totalHeight = dataSource.length * rowHeight
  },
  mounted() {
    this.scrollEle = document.querySelector('.c-large-table .sc .scbc');
    document.querySelector('.c-large-table .sc').addEventListener('scroll', this.handleScroll);
  },
  methods: {
    onShowSizeChange(current, pageSize) {
      this.$emit("onShowSizeChange", current, pageSize);
    },
    pageChange(current, pageSize) {
      this.$emit("onChange", current, pageSize);
    },
    handleTableChange() {
      
    },

    handleSelect(d, dl) {
      this.selectedRowKeys = d
      if(this.selected) this.$emit("selectChange", d, dl);
    },
    // 注意全选,需要手动填充数据
    handleSelectAll(d,dl) {
      let keys = [], dates = []
      if(d) {
        keys = this.dataSource.map(item => item.id)
        dates = [...this.dataSource]
      }
      this.handleSelect(keys, dates)
    },
    // 监听虚拟滚轮变化,计算展示的数据
    handleScroll(e) {
      const { scrollTop, scrollHeight } = e.target
      let lenMax = this.dataSource.length, nIdx;

      if(scrollTop === 0) {
        this.tableData = this.dataSource.slice(0, this.rows)
        this.idx = 0
      } else if(scrollTop === (scrollHeight - this.tableHeight)) {
        nIdx = lenMax - this.rows
        this.tableData = this.dataSource.slice(nIdx, nIdx + this.rows)
        this.idx = nIdx
      } else {
        nIdx = Math.ceil(scrollTop * lenMax / scrollHeight)
        if(nIdx !== this.idx && nIdx <= (lenMax - this.rows)) {
          this.tableData = this.dataSource.slice(nIdx, nIdx + this.rows)
          this.idx = nIdx
        }
      }
    },
  },
};
</script>

<style lang="less" >
  .c-large-table {
    position: relative;
    .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
      padding: 4px 10px;
    }
    .sc {
      position: absolute;
      top: 28px;
      right: -6px;
      width: 16px;
      overflow-x: hidden;
      overflow-y: scroll;
      .scbc {
        border-radius: 2px;
        background-color: #F1F1F1;
      }
    }
  }
</style>

 

posted @ 2020-09-16 16:29  Mr.聂  阅读(7766)  评论(4编辑  收藏  举报