vue2中的el-select组件数据太多,实现滚动加载数据效果

项目场景

在我们平常开发中,我们的下拉框数据大部分都是后端一次性返回,然后前端直接塞到页面渲染,我之前也是这么做的,但今天发现数据变得越来越多,已经有五百多条了,所以我就决定着手优化一下,怎么优化呢,比如 分页加载?虚拟列表?


问题描述

当我们使用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('触底加载数据');
         }
   }

如果感觉滚动监听太频繁,可以加个节流处理,我这里没有加

### 解决方案 对于 `el-tree-select` 件在处理大量数据时遇到的性能问题,可以采取种策略来优化其表现。以下是几种有效的解决方案: #### 1. 虚拟滚动技术的应用 虚拟滚动是一种只渲染当前视口内的项目的技术,从而减少 DOM 元素的数量并提高页面响应速度。Element Plus 提供了支持此功能的相关件或插件。 ```javascript import VirtualList from 'vue-virtual-scroll-list'; Vue.use(VirtualList); ``` 通过引入第三方库如 `vue-virtual-scroll-list` 或者其他类似的实现方式,可以在不显著影响用户体验的情况下大幅度提升加载效率[^1]。 #### 2. 数据加载机制 当面对庞大的树形结构时,采用按需加载的方式能够有效降低初始请求的数据量以及前端解析的压力。设置属性 `lazy=true` 并提供相应的异步方法用于动态获取子节点信息即可开启该特性。 ```html <el-tree-select v-model="value" :data="orgList" lazy :load="loadNode"></el-tree-select> ``` ```javascript methods: { loadNode(node, resolve) { if (node.level === 0) { return resolve([{ name: 'root' }]); } setTimeout(() => { const nodes = Array.from({ length: Math.ceil(Math.random() * 5 + 1)}, (_, i) => ({ id: node.data.id ? `${node.data.id}-${i}` : '' + i, label: `child-${i}`, leaf: Math.floor(10 * Math.random()) !== i })); resolve(nodes); }, 500); } } ``` 这种方法特别适用于层级较深且每层分支较的情况,在实际开发过程中可根据业务逻辑调整具体的加载规则。 #### 3. 减少不必要的计算开销 观察到原始代码片段中存在的监听器可能会频繁触发更新操作,这会带来额外的性能损耗。因此建议仅保留必要的事件处理器,并尽可能简化内部逻辑以加快执行速度。 例如原 `watch` 中对 `selectTree` 的监控可以通过更高效的方式来替代,比如利用 computed 属性代替复杂的过滤映射过程;而对于输入框的内容变化,则应考虑增加防抖动(debounce)函数防止过度调用 API 请求或其他耗时任务。 ```javascript computed: { filteredUsers() { return this.selectTree.filter(item => item.type === "user"); }, }, ... debounceFilterText(value){ clearTimeout(this.timeoutId); this.timeoutId=setTimeout(()=>{ this.$refs.orgtxtree.filter(value); },300) } watch:{ filterText: debounceFilterText, } ``` 此外还可以尝试移除未使用的变量声明(如 `list`),进一步精简源码。 #### 4. 自定义样式与布局优化 虽然这不是直接针对性能改进的方法,但是合理的视觉设计同样有助于改善整体交互体验。按照之前提到的做法给相关件添加特定 class 名字以便于后续 CSS 定制化工作,确保即使是在高并发场景下也能保持良好的可读性和易用性[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值