el-table 性能优化

在开发过程中,发现⼀个⻚⾯,有⼤量的横向表格数据。导致⻚⾯卡顿严重。⻚⾯中 DOM 元 素过多,导致渲染及其缓慢。

之所以会导致卡顿,因为⻚⾯元素过多。

推荐使用:JavaScript Data Grid: Documentation(插件ag-grid)

 横向滚动,⽐纵向滚动渲染时间更⻓。因为 element ui 对于 el-table 的设计,上⾯表头部 分是⼀个table,下⾯body部分也是⼀个table。 纵向滚动,可以分⻚。横向滚动,分⻚就不好⽤了。 因此采⽤虚拟滚动模式。

什么是虚拟滚动

⼀般的滚动,给⼀个固定⾼度,超出内容,就会展⽰滚动条,可以滚动。 虚拟滚动其实没有滚动,只是通过监听滚轮向上或向下滚动距离,计算当前要显⽰ 的内容列表的索引。因此,渲染的只是视⼝+缓冲部分,元素要少很多。

如上图,我们只渲染可视区域能⻅到的3,4,5,6这⼏个元素,⽽其他的都不会被渲 染。

模拟滚动

由于只渲染“看得⻅”的部分,因此是没有原⽣滚动功能的。需要取模拟滚动⾏为。在⽤ 户滚动滑轮或者划动屏幕时,相应的根据滚动距离, “滚动”内容列表。(⾮真正的滚 动,根据滚动位置重新渲染可⻅的列表元素)。 当这个操作时间跨度⾜够⼩时,它看起来就像是在滚动⼀样。 

这有点像我们在画帧动画⼀样,每次⽤户滑动造成偏移量改变,我们都会根据这个偏移 量去渲染新的列表元素。就像是在⼀帧⼀帧的播放动画⼀样,当两帧间隔⾜够⼩时,动 画看起来就会很流畅,就像是在滚动⼀样。 

横向滚动 

横向普通滚动

横向普通滚动

<template>
<div class="container">
<div class="header">
<el-button @click="gernateData(10, 500)">500列</el-button>
<el-button @click="gernateData(10, 1000)">1000列</el-button>
</div>
<!-- <div class="listWrapper" ref="listWrap" @scroll="onScroll"> -->
<!-- <div class="listWrapper" ref="listWrap">
<div
class="scrollWraper"
ref="list"
:style="{ width: `${allColumns.length * 150}px`, height: '1px' }"
></div> -->
<el-table border :data="tableData" ref="tableBox" v-loading="loading">
<!-- force-scroll="horizontal" -->
<el-table-column
v-for="col in virtualColumns"
:key="col.key"
:prop="col.key"
:label="col.name"
width="150"
align="right"
:formatter="formatCellThousand"
/>
</el-table>
<!-- </div> -->
</div>
</template>
<script>
export default {
name: "normal-horizontal-scroll",
data() {
return {
loading: false,
tableData: [],
allColumns: [],
virtualColumns: [],
startCol: 0,
endCol: 20,
};
},
computed: {
// virtualColumns() {
// return this.allColumns.slice(this.startCol, this.endCol)
// }
},
methods: {
generateColumns(num) {
const columns = [];
for (let i = 0; i < num; i++) {
columns.push({
key: `col${i}`,
name: `列${i}`,
});
}
this.allColumns = columns;
},
gernateData(rows, cols) {
this.loading = true;
setTimeout(() => {
this.generateColumns(cols);
const data = [];
for (let row = 0; row < rows; row++) {
const item = {};
for (let i = 0; i < cols; i++) {
item[`col${i}`] = `row${row}-col${i}`;
}
data.push(item);
}
this.tableData = data;
this.loading = false;
this.calcColumns(cols);
}, 500);
},
formatCellThousand(row, column, cellValue) {
return "$:" + cellValue;
},
calcColumns(eCol) {
const endCol = eCol || this.endCol;
this.virtualColumns = this.allColumns.slice(this.startCol, endCol);
},
onScroll() {
const scrollLeft = this.$refs.listWrap.scrollLeft;
console.log(scrollLeft);
console.log(this.$refs.listWrap.scrollWidth);
console.log(this.$refs.listWrap.clientWidth);
const newIndex = Math.floor(scrollLeft / 150);
if (newIndex !== this.startCol) {
this.startCol = Math.floor(scrollLeft / 150);
this.endCol = this.startCol + 20;
this.$refs.tableBox.$el.style.marginLeft = `${scrollLeft}px`;
this.calcColumns();
}
if (scrollLeft === 0) {
this.$refs.tableBox.$el.style.marginLeft = `${scrollLeft}px`;
}
},
},
};
</script>
<style>
.container {
padding: 20px;
}
.header {
margin-bottom: 20px;
}
.listWrapper .el-table__body-wrapper {
overflow-x: hidden !important;
}
.listWrapper {
overflow-x: auto;
}
</style>

横向虚拟滚动

<template>
<div class="container">
<div class="header">
<el-button @click="gernateData(10, 500)">500列</el-button>
<el-button @click="gernateData(10, 1000)">1000列</el-button>
</div>
<div class="listWrapper" ref="listWrap" @scroll="onScroll">
<div
class="scrollWraper"
ref="list"
:style="{ width: `${allColumns.length * 150}px`, height: '1px' }"
></div>
<el-table
border
:data="tableData"
ref="tableBox"
v-loading="loading"
force-scroll="horizontal"
>
<el-table-column
v-for="col in virtualColumns"
:key="col.key"
:prop="col.key"
:label="col.name"
width="150"
align="right"
:formatter="formatCellThousand"
/>
</el-table>
</div>
</div>
</template>
<script>
export default {
name: "index-home",
data() {
return {
loading: false,
tableData: [],
allColumns: [],
virtualColumns: [],
startCol: 0,
endCol: 20,
};
},
computed: {
// virtualColumns() {
// return this.allColumns.slice(this.startCol, this.endCol)
// }
},
methods: {
generateColumns(num) {
const columns = [];
for (let i = 0; i < num; i++) {
columns.push({
key: `col${i}`,
name: `列${i}`,
});
}
this.allColumns = columns;
},
gernateData(rows, cols) {
this.loading = true;
setTimeout(() => {
this.generateColumns(cols);
const data = [];
for (let row = 0; row < rows; row++) {
const item = {};
for (let i = 0; i < cols; i++) {
item[`col${i}`] = `row${row}-col${i}`;
}
data.push(item);
}
this.tableData = data;
this.loading = false;
this.calcColumns();
}, 500);
},
formatCellThousand(row, column, cellValue) {
return "$:" + cellValue;
},
calcColumns() {
this.virtualColumns = this.allColumns.slice(this.startCol, this.endCol);
},
onScroll() {
const scrollLeft = this.$refs.listWrap.scrollLeft;
console.log(scrollLeft);
console.log(this.$refs.listWrap.scrollWidth);
console.log(this.$refs.listWrap.clientWidth);
const newIndex = Math.floor(scrollLeft / 150);
if (newIndex !== this.startCol) {
this.startCol = Math.floor(scrollLeft / 150);
this.endCol = this.startCol + 20;
this.$refs.tableBox.$el.style.marginLeft = `${scrollLeft}px`;
this.calcColumns();
}
if (scrollLeft === 0) {
this.$refs.tableBox.$el.style.marginLeft = `${scrollLeft}px`;
}
},
},
};
</script>
<style>
.container {
padding: 20px;
}
.header {
margin-bottom: 20px;
}
.listWrapper .el-table__body-wrapper {
overflow-x: hidden !important;
}
.listWrapper {
overflow-x: auto;
}
</style>

纵向滚动 

纵向普通滚动

<template>
<div class="container">
<div class="header">
<el-button @click="generateData(500)">500⾏</el-button>
<el-button @click="generateData(1000)">1000⾏</el-button>
</div>
<el-table :data="tableData" v-loading="loading" max-height="528">
<el-table-column
v-for="col in columnLength"
:key="col"
:prop="col + ''"
:label="`第${col}列`"
></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "normal-vertical-scroll",
data() {
return {
loading: false,
tableData: [],
columnLength: 10,
};
},
methods: {
generateData(row) {
this.loading = true;
setTimeout(() => {
const columns = [];
for (let i = 0; i < row; i++) {
const obj = {};
for (let j = 0; j < this.columnLength; j++) {
obj[j + 1] = `第${i + 1}⾏-第${j + 1}列`;
}
columns.push(obj);
}
this.loading = false;
console.log(columns);
this.tableData = columns;
}, 500);
},
},
};
</script>
<style>
.container {
padding: 20px;
}
.header {
margin-bottom: 20px;
}
</style>

 纵向虚拟滚动

<template>
<div class="container">
<div class="header">
<el-button @click="generateData(500)">500⾏</el-button>
<el-button @click="generateData(1000)">1000⾏</el-button>
</div>
<div class="list-column-wrapper" ref="listWrap" @scroll="onScroll">
<div
class="scroll-wrapper"
ref="list"
:style="{
height: `${allRows.length * 48}px`,
width: '1px',
}"
></div>
<el-table :data="tableData" ref="tableBox" v-loading="loading">
<el-table-column
v-for="col in columnLength"
:key="col"
:prop="col + ''"
:label="`第${col}列`"
></el-table-column>
</el-table>
</div>
</div>
</template>
<script>
export default {
name: "virtual-vertical-scroll",
data() {
return {
loading: false,
tableData: [],
allRows: [],
columnLength: 10,
startRow: 0,
endRow: 10,
};
},
mounted() {
this.$refs.tableBox.style.height = "528px";
},
methods: {
calcRows(list) {
console.log("startRow", this.startRow);
console.log("endRow", this.endRow);
this.tableData = list.slice(this.startRow, this.endRow);
},
generateData(row) {
this.loading = true;
setTimeout(() => {
const columns = [];
for (let i = 0; i < row; i++) {
const obj = {};
for (let j = 0; j < this.columnLength; j++) {
obj[j + 1] = `第${i + 1}⾏-第${j + 1}列`;
}
columns.push(obj);
}
this.loading = false;
this.allRows = columns;
this.calcRows(this.allRows);
}, 500);
},
onScroll() {
const scrollTop = this.$refs.listWrap.scrollTop;
console.log(scrollTop);
const newIndex = Math.floor(scrollTop / 48);
if (newIndex !== this.startRow) {
this.startRow = Math.floor(scrollTop / 48);
this.endRow = this.startRow + 10;
this.$refs.tableBox.$el.style.marginTop = `${scrollTop}px`;
this.$refs.tableBox.$el.style.overflow = "visible";
this.calcRows(this.allRows);
}
if (scrollTop === 0) {
this.$refs.tableBox.$el.style.marginTop = `${scrollTop}px`;
}
},
},
};
</script>
<style>
.container {
padding: 20px;
}
.header {
margin-bottom: 20px;
}
.list-column-wrapper .el-table__body-wrapper {
overflow-y: hidden !important;
}
.list-column-wrapper {
display: flex;
overflow-y: auto;
max-height: 528px;
}
</style>

猜你喜欢

转载自blog.csdn.net/aZHANGJIANZHENa/article/details/128232209