表格最大數據量也就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>
