项目场景
在我们平常开发中,我们的下拉框数据大部分都是后端一次性返回,然后前端直接塞到页面渲染,我之前也是这么做的,但今天发现数据变得越来越多,已经有五百多条了,所以我就决定着手优化一下,怎么优化呢,比如 分页加载?虚拟列表?
问题描述
当我们使用el-select下拉框选择数据的时候,避免不了数据过多,导致一上来渲染到页面会出现卡顿现象,比如说四五百条数据,一下子塞到下拉框中,页面刚开始渲染的时候,页面许多地方都在渲染数据、重排、重绘,数据少还可以,数据太多会影响性能。
解决方案:
el-select给我们提供了 支持远程搜索的功能,这样我们可以一次渲染少许数据,剩下数据可以通过搜索获取。但有时候 我不知道要搜索的数据名字叫什么,从而导致无法有效搜索,还有就是每次搜索都要请求一次数据,其实官方这个优化已经解决大部分场景问题了。
对于el-select的场景,显然 虚拟列表 不是最优的,因为虚拟列表会把视口外的元素从dom树里移出去,导致我们选择的数据状态无法保存,所以我决定使用分页加载 。后端刚开始一次性把所有数据返回给我,然后前端分批进行渲染,如果后端一次性请求所有数据太慢,也可以分批加载,具体可以与后端沟通。
代码如下:
一开始先拿20条数据,渲染页面,声明一个变量保存所有数据
//html结构
<el-select v-model="hospital" @visible-change="visible" placeholder="请选择医院" filterable collapse-tags multiple @change='changeHospital'>
<el-option :disabled="loading" :label="item.hospital_name" :value="item.hospital_id" v-for="(item,index) in hospitalList" :key="item.hospital_id"></el-option>
</el-select>
//js代码
// 下拉框出现的时候事件
visible(val){
//如果多个下拉框,需要具体给某个标签绑定
let scroll = document.querySelectorAll('.el-scrollbar__wrap')
//显示的时候绑定,隐藏的时候移出绑定事件
if(val){
scroll[1].addEventListener('scroll',this.scrollLoad)
}else{
scroll[1].removeEventListener('scroll',this.scrollLoad)
}
},
// 下拉框滚动分页加载数据
scrollLoad(e){
const { target: { clientHeight,scrollHeight,scrollTop } } = e
const step = 100 //间隔,距离底部100的时候加载数据
const len = this.hospitalList.length //获取当前展示的医院列表长度
if(len >= this.hospital_list.length)return //数据加载完毕
//从总列表里每次 截取一段数据,以便后期追加到页面
// 每次追加20条
const data = this.hospital_list.slice(len,len + 20)
//判断触底加载数据
if(clientHeight + scrollTop >= scrollHeight - step){
this.hospitalList.push(...data)
console.log('触底加载数据');
}
}
如果感觉滚动监听太频繁,可以加个节流处理,我这里没有加