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>