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>

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
fu-tableel-table都是前端开发中用于构建表格组件的库,它们分别来自不同的开源项目: 1. **vue-fu-table**: 这是一个基于Vue.js的轻量级表格组件库,它的设计目标可能是提供更简洁、易用的API以及更好的性能优化。fu-table可能专注于底层实现的灵活性,适合对性能有较高要求或者想要定制化程度更高的开发者。 2. **Element UI** (简称El-Table): Element UI是由饿了么团队开发的一个完善的UI组件套件,其中包括el-table,它提供了丰富的功能和高度可定制化的选项,比如列分隔线、合并单元格、排序、过滤等,而且通常有更好的文档支持和社区资源。Element UI是基于Vue.js的,所以它的组件往往已经内建了响应式和生命周期钩子等功能。 两者的区别主要体现在以下几个方面: - **生态系统**:El-Table隶属于一个完整的UI库,包含了其他组件和工具,而fu-table相对独立,可能没有那么全面的功能集。 - **功能丰富度**:El-Table通常包含更多的预置功能和交互效果,对于快速上手和基本场景来说较为方便;而fu-table可能会更侧重于基础功能,允许更多自定义。 - **灵活性和定制性**:fu-table可能更加灵活,对于高级开发者或希望深入控制组件内部的用户来说更合适。 - **学习曲线**:由于Element UI的广泛使用,El-Table的学习曲线相对平缓;而fu-table可能需要更多时间去理解和适应。 如果你正在寻找一个简单快速搭建表格的应用,El-Table可能是首选;如果追求极致的灵活性和高性能,或者想深入了解组件内部机制,fu-table则是个不错的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JianZhen✓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值