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>
相关推荐
大得36916 分钟前
electron结合vue,直接访问静态文件如何跳转访问路径
javascript·vue.js·electron
水银嘻嘻2 小时前
12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建
运维·前端·自动化
小嘟嚷ovo3 小时前
h5,原生html,echarts关系网实现
前端·html·echarts
十一吖i3 小时前
Vue3项目使用ElDrawer后select方法不生效
前端
只可远观3 小时前
Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件
前端·flutter
周胡杰3 小时前
组件导航 (HMRouter)+flutter项目搭建-混合开发+分栏效果
前端·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
敲代码的小吉米3 小时前
前端上传el-upload、原生input本地文件pdf格式(纯前端预览本地文件不走后端接口)
前端·javascript·pdf·状态模式
是千千千熠啊3 小时前
vue使用Fabric和pdfjs完成合同签章及批注
前端·vue.js
九月TTS4 小时前
TTS-Web-Vue系列:组件逻辑分离与模块化重构
前端·vue.js·重构
我是大头鸟5 小时前
SpringMVC 内容协商处理
前端