背景
穿梭框处理大数据量时,由于渲染的 DOM 节点过多,造成页面卡顿的问题。
在尽量不改变组件原有逻辑的前提下,进行优化。
解决思路
懒加载 - InfiniteScroll 组件
先从 packages/transfer 中将原组件拷出(或者改源码重新打包维护私有库使用)
将
v-infinite-scroll="pageDown"
:infinite-scroll-immediate="false"
添加到
<el-checkbox-group
v-show="!hasNoMatch && data.length > 0"
v-model="checked"
:size="size"
:class="{ 'is-filterable': filterable }"
class="el-transfer-panel__list"
v-infinite-scroll="pageDown"
:infinite-scroll-immediate="false"
>
<el-checkbox
class="el-transfer-panel__item"
:label="item[keyProp]"
:disabled="item[disabledProp]"
:key="item[keyProp]"
v-for="item in filteredData">
<option-content :option="item"></option-content>
</el-checkbox>
</el-checkbox-group>
在data中定义pageSize: 20 用来表示每页数据个数showData: [] 仅用来展示使用,替换上述代码中实际需要操作的数据 filteredData
v-for="item in showData">
同时在watch中相应的处理
data (data) {
const checked = [];
this.showData = data.slice(0, this.pageSize);
const filteredDataKeys = this.filteredData.map(
(item) => item[this.keyProp]
);
this.checked.forEach((item) => {
if (filteredDataKeys.indexOf(item) > -1) {
checked.push(item);
}
});
this.checkChangeByUser = false;
this.checked = checked;
},
filteredData (filteredData) {
this.showData = filteredData.slice(0, this.pageSize);
}
初始化展示数量随意这里取 20。
最后添加滚动到底部时调用的方法
pageDown () {
const l = this.showData.length;
const totalLength = this.filteredData.length
l < totalLength &&
(this.showData = this.filteredData.slice(0, l + this.pageSize > totalLength ?
totalLength : l + this.pageSize));
},
往下滚动的时候 展示的数据长度增加 20(数量随意), 超出时展示最大长度。
由此基本解决大数据量操作卡顿的问题。由于展示和逻辑层分开,组件的所有操作逻辑无须修改,最小程度减少差异。
新问题
手动滚动到列表末端,再进行搜索操作依然存在卡顿问题。
进阶
在滚动过程中,实际上顶端的数据依旧无法看见,该数据不展示,对用户体验也没有影响,
所以只需展示当前页的 20 条数据。
我们为el-checkbox-group添加一个 ref=scrollContainer 以便操作滚动条,
在data中定义当前页数 curIndex: 1
并对 pageDown 方法进行修改
pageDown () {
const totalLength = this.filteredData.length
if((this.curIndex*this.pageSize) < totalLength){
this.curIndex ++
const targetLength = this.curIndex * this.pageSize
const endPoint = targetLength > totalLength ? totalLength : targetLength
const startPoint = endPoint - this.pageSize > 0 ? endPoint - this.pageSize : 0
this.showData = this.filteredData.slice(startPoint, endPoint);
this.$refs.scrollContainer.$el.scrollTop = "1px" //滚动条到最上端,衔接下一页,为 0 可能会触发边界问题
}
}
为此我们还需要添加向上翻页的方法
InfiniteScroll 指令 只提供向下滚动,我们可以拓展该指令亦可自行添加上滑滚动监听
mounted(){
this.$refs.scrollContainer.$el.addEventListener('scroll', this.pageUp)
},
beforeDestroy(){
this.$refs.scrollContainer.$el.removeEventListener('scroll', this.pageUp)
},
注册pageUp 方法
pageUp(e){
if(e.target.scrollTop ===0 && this.curIndex>1){
this.curIndex --
const endPoint = this.curIndex * this.pageSize
const startPoint = (this.curIndex-1)* this.pageSize
this.showData = this.filteredData.slice(startPoint, endPoint);
const el = this.$refs.scrollContainer.$el
el.scrollTop = el.scrollHeight - el.clientHeight - 1 // 滚动到最底部,衔接上一页, -1 防止边界问题。
}
},
当进行数据操作的时候,页面内容变化,滚动条也会随之变化,为防止不能预知的翻页,数据改变时,重置滚动条和当前页码。
initScroll(){
this.curIndex = 1
this.$refs.scrollContainer.$el.scrollTop = 0
},
同时地,在watch中相应时候执行 initScroll
data(){
...
this.initScroll()
...
},
filteredData (filteredData) {
...
this.initScroll()
}
至此大数据量的穿梭框,性能大为改善。
到此这篇关于element 穿梭框性能优化的实现的文章就介绍到这了,更多相关element 穿梭框性能优化内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论