vue el-select数据量太大,导致浏览器崩溃解决办法

文章介绍了一种处理大量下拉数据时浏览器渲染缓慢甚至崩溃的解决方案。通过使用Vue.js的懒加载策略,结合el-select组件的filter-method和自定义指令v-el-select-loadmore,实现分页加载,仅在需要时加载更多数据,从而优化性能并防止浏览器崩溃。同时,文章还涉及到了滚动条定位的处理方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下拉数据量太大,浏览器单线程渲染时间较长,会导致浏览器崩溃。为了解决这一问题,可以采用懒加载形式,完美解决

<el-col :span="24">
              <el-form-item label="入库物资"  prop="mids">
                  <el-select v-model="mids" value-key="matId" multiple collapse-tags filterable :filter-method="filterMethod" placeholder="请选择需要入库的物资"
                  :popper-append-to-body="false"
                  v-el-select-loadmore="loadmore" 
                  ref="containerSelect"
                  @change="selectChanged($event)"
                  style="width: 100% ">
                    <el-option
                      v-for="item in materialList"
                      :key="item.matId"
                      :label="`${item.matName}`"
                      :value="item">
                    </el-option>
                  </el-select>
              </el-form-item>
          </el-col>

以上是下拉框代码段

:filter-method="filterMethod"自定义筛选方法,支持筛选

v-el-select-loadmore="loadmore" 懒加载方法

directives: {
    'el-select-loadmore':{
      bind(el, binding){
        const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
        SELECTWRAP_DOM.addEventListener('scroll', function(){
          /**
            * scrollHeight 获取元素内容高度(只读)
            * scrollTop 获取或者设置元素的偏移值,常用于计算滚动条的位置,当一个元素的容器没有产生垂直方向的滚动条,那它的scrollTop值默认为0
            * clientHeight 获取元素的可见高度(只读)
            * 如果元素滚动到底,下面的等式返回true,没有则返回false
            * 
          **/
          const condition = (this.scrollHeight - this.scrollTop) <= (this.clientHeight+10);
          if(condition){
            binding.value();
          }
        })
      }
    }
  },

以上代码段跟data()同级别

data() {
    return {
    //懒加载下拉列表--start
      resourceTotal:0,
      resourceNum:1,
      resourcePage:10,
      resourceName:'',
      resourceOption:[],
    //懒加载下拉列表--end
}
}
/** 查询物资列表 */
    getListNoPage() {
      matListNoPage(this.query).then(response => {
        this.materialAllList = response.data;
        this.resourcePage = 10
        this.resourceNum = 1
        //由于物资太多,默认展示前500条
        this.materialList = response.data.slice(0,this.resourcePage);
        this.resourceTotal = this.materialList.length;
        this.resourceOption = this.materialAllList
      });
    },
    filterMethod(query){ //query是输入的关键字
        this.resourceName = query
        this.resourcePage = 10
        this.resourceNum = 1
        if(query == ''){            
            this.materialList = this.materialAllList.slice(0,this.resourcePage)
            this.resourceOption = this.materialAllList
        }else{
            let result = [] //存储符合条件的下拉选项
            this.materialAllList.forEach(val=>{
                if(val.matName.indexOf(query)!=-1) result.push(val)
            })
            this.resourceOption = result
            this.materialList = result.slice(0,this.resourcePage) //只取前500个
        }
        this.resourceTotal = this.materialList.length;
       //下拉选项更改的时候设置滚动条高度为0
        this.$refs.containerSelect.$refs.scrollbar.wrap.scrollTop = 0;
    },
    //懒加载下拉列表--start
    loadmore(){
      if(this.resourceTotal === this.resourcePage){
        this.resourceNum++;
        this.searchLoadResource();
      }
    },
    searchLoadResource(){
      let result = []
      if(this.resourcePage*this.resourceNum < this.resourceOption.length){
        result = this.resourceOption.slice(this.resourcePage*(this.resourceNum-1),this.resourcePage*this.resourceNum)
      }else{
        result = this.resourceOption.slice(this.resourcePage*(this.resourceNum-1),this.resourceOption.length)
      }
      this.resourceTotal = result.length;
      if(this.materialList.length > 0){
        var pushFlg = '';
        // 这个循环是因为下拉框滚动条的时候,有时会揍两遍方法,导致数据重复添加
        // 循环中的判断是为了不让数据重复添加
        for(var i =0; i < result.length; i++){
          if(this.materialList.findIndex(item => item.matId === result[i].matId) < 0){
            pushFlg = 'push';
            break;
          }
        }
        if(pushFlg === 'push'){
          this.materialList = this.materialList.concat(result);
        }
      }else{
        this.materialList = result;
      }
    },
    //懒加载下拉列表--end

下拉选项变化时候涉及到滚动条定位问题,el-select设置滚动条再最顶端,复制下面代码即可

//下拉选项更改的时候设置滚动条高度为0
        this.$refs.containerSelect.$refs.scrollbar.wrap.scrollTop = 0;

### Vue2 `el-select` 处理大量数据时的性能优化解决方案 #### 使用虚拟滚动提升渲染效率 为了应对大数据量带来的性能挑战,可以引入虚拟列表技术来减少一次性渲染的 DOM 节点数量。Element Plus 社区提供了基于 vue-virtual-scroller 的插件支持[^1]。 ```javascript import VirtualSelect from &#39;vue-virtual-scroll-list&#39;; export default { components: { VirtualSelect, }, }; ``` #### 数据懒加载机制 对于选项较多的情况,建议采用分页或无限滚动的方式按需加载数据,而不是一开始就全部加载到内存中。这不仅节省资源开销,还能显著改善用户体验。 ```html <template> <el-select v-model="value" filterable remote :remote-method="loadData"> <!-- ... --> </el-select> </template> <script> methods: { loadData(queryString) { this.loading = true; setTimeout(() => { // 模拟异步请求获取远程数据 const results = mockData.filter(item => item.label.toLowerCase().includes(queryString.toLowerCase()) ); this.options = results.slice(0, 10); // 只显示前十个匹配项 this.loading = false; }, 300); } } </script> ``` #### 配置合理的缓存策略 当存在重复查询相同关键字的情形时,可以通过设置本地缓存(如 sessionStorage 或 localStorage),避免不必要的网络请求,提高响应速度并减轻服务器压力。 #### 动态调整组件内部属性 针对特定场景下的特殊需求,比如初始化时不希望立即展开下拉菜单,则可通过控制 `popper-append-to-body` 属性实现延迟挂载效果;另外还可以利用 `reserve-keyword` 参数保持输入框内的关键词不变以便用户继续编辑。 #### 解决赋值无效问题 如果遇到类似 adjustmentDetailList 中的数据动态添加后无法正常选中的情况,应该确保每次更新状态都触发视图重新计算。一种方法是在变更数组之后调用 `$nextTick()` 方法等待DOM 更新完成再执行后续逻辑[^2]。 ```javascript this.adjustmentDetailList.push(newItem); this.$nextTick(() => { // 执行依赖于新加入元素的操作 }); ``` #### 确保 change 事件即时响应 为了避免 el-select 的 change 事件滞后现象,在修改关联字段的同时应当同步刷新表单验证状态以及相关联控件的状态。此外,使用 Promise 来封装异步操作有助于更好地管理流程顺序[^3]。 ```javascript async acctChange(val) { try { let result = this.acctList.find((item) => item.AcctNo1 === val); if (!result) return; let response = await apiCall({ menuId: this.menuId, medAcctNo: val, currency: result.AcctCcy1, bankAcType: result.BankAcType, signature: result.signature, }); Object.assign(this.ruleForm, { repayAcBalance: response.workingBal, currency: response.currency, }); } catch (error) { console.error(&#39;Failed to update account info:&#39;, error); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值