el-select处理大量数据,实现选择和搜索

背景

在项目开发中,有时候我们会遇到数据量大,搜索框加载缓慢甚至数据量达到一定程度时会出现卡顿甚至卡死的现象,这时候为了解决这一问题通常会使用到虚拟列表方法。

思想

每次只渲染自己自定义的数量,通过滚动条的变化来加载每一轮的数据。

官网地址:https://tangbc.github.io/vue-virtual-scroll-list/#/

操作

安装插件:

npm install vue-virtual-scroll-list --save

使用

  • father.vue文件
<SelectCode
     ref="Select"
     :selectData="selectData"
     v-model="defaultValue"
     placeholder="请选择"
     clearable
></SelectCode>
     defaultValue: "",
     selectData: {
        data: [], // 下拉框数据
        label: "label", // 下拉框需要显示的名称
        value: "key", // 下拉框绑定的值
        isRight: true, //右侧是否显示
      },
  •  selectCode.vue文件
<el-select
      :value="defaultValue"
      popper-class="virtualselect"
      filterable
      :filter-method="filterMethod"
      @visible-change="visibleChange"
      v-bind="$attrs"
      v-on="$listeners"
      style="width: calc(100% - 24px)"
      :popper-append-to-body="false"
    >
      <virtual-list
        ref="virtualList"
        class="virtualselect-list"
        :data-key="selectData.value"
        :data-sources="selectArr"
        :data-component="itemComponent"
        :keeps="20"
        :extra-props="{
          label: selectData.label,
          value: selectData.value,
          isRight: selectData.isRight,
        }"
      ></virtual-list>
    </el-select>
<script>
import virtualList from "vue-virtual-scroll-list";
import ElOptionNode from "./el-option-node";
export default {
  components: {
    "virtual-list": virtualList,
  },
  model: {
    prop: "defaultValue",
    event: "change",
  },
  props: {
    selectData: {
      type: Object,
      default() {
        return {};
      },
    }, //父组件传的值
    defaultValue: {
      type: String,
      default: "",
    }, // 绑定的默认值
  },
  mounted() {
    this.init();
  },
  watch: {
    "selectData.data"() {
      this.init();
    },
  },
  data() {
    return {
      itemComponent: ElOptionNode,
      selectArr: [],
    };
  },
  methods: {
    init() {
      if (!this.defaultValue) {
        this.selectArr = this.selectData.data;
      } else {
        // 回显问题
        // 由于只渲染20条数据,当默认数据处于20条之外,在回显的时候会显示异常
        // 解决方法:遍历所有数据,将对应回显的那一条数据放在第一条即可
        this.selectArr = JSON.parse(JSON.stringify(this.selectData.data));
        let obj = {};
        for (let i = 0; i < this.selectArr.length; i++) {
          const element = this.selectArr[i];
          if (
            element[this.selectData.value].toLowerCase() ===
            this.defaultValue.toLowerCase()
          ) {
            obj = element;
            this.selectArr.splice(i, 1);
            break;
          }
        }
        this.selectArr.unshift(obj);
      }
    },
    // 搜索
    filterMethod(query) {
      if (query !== "") {
        this.$refs.virtualList.scrollToIndex(0); //滚动到顶部
        setTimeout(() => {
          this.selectArr = this.selectData.data.filter((item) => {
            return this.selectData.isRight
              ? item[this.selectData.label]
                  .toLowerCase()
                  .indexOf(query.toLowerCase()) > -1 ||
                  item[this.selectData.value]
                    .toLowerCase()
                    .indexOf(query.toLowerCase()) > -1
              : item[this.selectData.label]
                  .toLowerCase()
                  .indexOf(query.toLowerCase()) > -1;
          });
        }, 100);
      } else {
        this.init();
      }
    },
    visibleChange(bool) {
      if (!bool) {
        this.$refs.virtualList.reset();
        this.init();
      }
    },
  },
};

添加样式:

.virtualselect {
  // 设置最大高度
  &-list {
    max-height: 245px;
    overflow-y: auto;
  }
  /deep/ .el-scrollbar .el-scrollbar__bar.is-vertical {
    width: 0;
  }
}
  • ElOptionNode.vue文件
<template>
  <el-option :key="label + value" :label="source[label]" :value="source[value]">
    <span>{{ source[label] }}</span>
  </el-option>
</template>
<script>
export default {
  name: "item-component",
  props: {
    index: {
      type: Number,
    }, // 每一行的索引
    source: {
      type: Object,
      default() {
        return {};
      },
    }, // 每一行的内容
    label: {
      type: String,
    }, // 需要显示的名称
    value: {
      type: String,
    }, // 绑定的值
    isRight: {
      type: Boolean,
      default() {
        return false;
      },
    }, // 右侧是否显示绑定的值
  },
};
</script>

总结

使用虚拟列表能解决el-select遇到的数据量大的问题,更多使用方法请参考官网介绍。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值