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>
相关推荐
zhengxianyi5151 小时前
只需3句让Vue3 打包部署后通过修改配置文件修改全局变量——实时生效
vue.js·前后端分离·数据大屏·ruoyi-vue-pro优化
悟能不能悟1 小时前
前端上载文件时,上载多个文件,但是一个一个调用接口,怎么实现
前端
可问春风_ren2 小时前
前端文件上传详细解析
前端·ecmascript·reactjs·js
羊小猪~~2 小时前
【QT】--文件操作
前端·数据库·c++·后端·qt·qt6.3
晚风资源组3 小时前
CSS文字和图片在容器内垂直居中的简单方法
前端·css·css3
Miketutu4 小时前
Flutter学习 - 组件通信与网络请求Dio
开发语言·前端·javascript
QQ4022054965 小时前
python基于vue的大学生课堂考勤系统设计与实现django flask pycharm
vue.js·python·django
光影少年5 小时前
前端如何调用gpu渲染,提升gpu渲染
前端·aigc·web·ai编程
Surplusx6 小时前
运用VS Code前端开发工具完成网页头部导航栏
前端·html
小宇的天下6 小时前
Calibre 3Dstack --每日一个命令day13【enclosure】(3-13)
服务器·前端·数据库