el-select应用虚拟列表,避免过多数据导致浏览器卡死

el-select:

element-ui组件中的select下拉选择组件,支持单选、多选等

虚拟列表:

虚拟列表是一种优化技术,用于处理大型列表。在传统的列表中,当用户滚动到底部时,列表会加载所有的数据,这可能导致性能问题和内存泄漏。虚拟列表通过只加载当前可见的部分数据,而不是整个列表的数据来解决这个问题。当用户滚动到新的区域时,虚拟列表会自动加载新的数据,从而提高性能和响应速度。这种技术通常与虚拟滚动结合使用,可以在保持高性能和流畅性的同时,支持大量的数据呈现。

背景:

在做管理系统,下拉选择框是个必备功能,在实际开发中,下拉数据量是不可控的,el-select虽然有过滤筛选等功能,但是如果数据过大的时候,会导致浏览器卡死,在切换页面时,销毁这个也很耗时,导致页面切换体验性很差,所以需要处理这种情况!

最简单处理方案:

默认下拉是空,只支持过滤筛选,实现:filterMethod,可以手动控制展示的数据量

最终处理方案:

用虚拟列表策略处理,重新封装el-select组件

复制代码
<template>
  <el-select
    v-model="selected"
    :filter-method="filterMethod"
    :value-key="props.key ? props.key : props.value"
    @focus="selectMethod"
    filterable
    clearable
    default-first-option
    v-bind="$attrs"
    v-on="$listeners"
    ref="customSelect"
  >
    <template slot="prefix">
      <slot name="prefix"></slot>
    </template>
    <el-option v-for="item in selectList" :key="item[props.key ? props.key : props.value]" :value="item[props.value]" :label="item[props.label]"></el-option>
  </el-select>
</template>

<script>
import { throttle } from '@/utils/debounce';
export default {
  props: {
    value: [String, Number, Array],
    props: {
      type: Object,
      default: () => {
        return {
          value: 'id',
          label: 'name',
        };
      },
    },
    data: {
      type: Array,
      default: () => [],
    },
  },
  computed: {
    selected: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('input', val);
      },
    },
  },
  data() {
    return {
      scrollDom: null,
      selectList: [],
      filterList: [],
      page: 1,
      size: 20,
    };
  },
  watch: {
    data: {
      immediate: true,
      handler(val) {
        val.length && this.initSelect();
      },
    },
  },
  mounted() {
    this.scrollDom = this.$refs.customSelect.$refs.scrollbar.$refs.wrap;
    this.scrollDom.addEventListener('scroll', throttle(this.handlerScroll, 200));
  },
  beforeDestroy() {
    this.scrollDom.removeEventListener('scroll', throttle(this.handlerScroll, 200));
  },
  methods: {
    handlerScroll() {
      // TODO:监听滚动,触发加载
      if (this.scrollDom.scrollHeight - this.scrollDom.scrollTop - 1 <= this.scrollDom.clientHeight) {
        this.loadData();
      }
    },
    firstLoad() {
      // 初始化数据
      this.page = 1;
      const len = this.filterList.length;
      if (len <= this.size) {
        this.selectList = this.filterList;
      } else {
        this.selectList = this.filterList.slice(0, this.size);
      }
    },
    selectMethod() {
      let param = this.selected;
      if (Object.prototype.toString.call(this.selected) === '[object Array]') {
        param = this.selected.join('');
      }
      if (param) {
        // TODO:有值不需要重置查询, 但当组件初始化的时候selected有值回显有问题
      } else {
        this.filterMethod('');
      }
    },
    filterMethod(str) {
      this.filterList = this.data.filter(item => {
        return item[this.props.label] && item[this.props.label].indexOf(str) > -1;
      });
      this.firstLoad();
    },
    initSelect() {
      let param = this.selected;
      if (Object.prototype.toString.call(this.selected) === '[object Array]') {
        param = this.selected.join('');
      }
      if (param) {
        // 筛选
        this.filterList = this.data.filter(item => {
          return param.indexOf(item[this.props.value]) > -1;
        });
        this.selectList = this.filterList;
      }
    },
    loadData() {
      if (this.filterList.length <= this.page * this.size) {
        // 最后一页
        return;
      }
      ++this.page;
      const len = this.page * this.size;
      if (this.filterList.length <= len) {
        this.selectList = this.filterList;
      } else {
        this.selectList = this.filterList.slice(0, len);
      }
    },
  },
};
</script>
相关推荐
鬼手点金2 小时前
nanoGPT/nanochat 能做出 DeepSeek/Qwen 这样的大模型吗?
服务器·前端·javascript·bug·openclaw
蛋蛋的就会顺顺的2 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
程序员Sunday2 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室2 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
码艺-Alimjan3 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床3 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a4 小时前
【文件上传】一个普普通通的edu16
前端
美狐美颜SDK开放平台5 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
pride.li5 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
屏什么录6 小时前
电脑如何录屏幕视频和声音?从工具到代码,7 种方案帮你彻底搞定
前端·音视频开发