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 小时前
Bun v1.4.1 深度解析:从 Zig 到 Rust,一场 11 天、64 个 AI 代理的语言迁徙
前端·后端·bun
人民广场吃泡面2 小时前
什么是AI Agent?它又能给前端带来哪些效率提升?
前端·人工智能
中科三方2 小时前
两家域名注册商资质被ICANN终止:企业域名资产安全再受关注
前端·网络·安全·域名
bug总结3 小时前
uniapp vue3全局方法注册使用
前端·javascript·uni-app
华无丽言3 小时前
如何在宜搭中实现获取子表中的字段值赋值到父表中?
前端·javascript·低代码
IT_陈寒4 小时前
Vue的computed属性竟然坑了我一把
前端·人工智能·后端
威斯软科的老司机4 小时前
通俗讲解 CNN 图像识别、向量 Embedding、Softmax 概率计算这三块的简化原理
前端·人工智能·ui·数字孪生
泯泷5 小时前
手搓JSVM第 12 篇:完整最小 JSVM 实现与源码设计复盘
前端·javascript·前端框架
默_笙5 小时前
🍔 给 AI 发一张结构化表格(下):从"自由发挥"到"按格填空"的输出驯服指南
前端·javascript
泯泷5 小时前
手搓JSVM第 11 篇:打包、模块与 CLI:把 VM 产物变成可运行文件
前端·javascript·前端框架