解决el-select数据量过大卡顿问题-记录贴

1,596 阅读1分钟

element组件当数据量过大会出现卡顿明显的现象

通过滚动显示更多数据解决卡顿问题

el-select封装

image.png

// 控件名称  LargeDataSearchSelect


const debounce = (fun, delay = 500) => {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fun.apply(this, args);
    }, delay);
  };
};
// 数字 字符串 function是不需要拷贝的
const deepClone = (value) => {
  if (value == null) return value;
  if (typeof value !== "object") return value;
  if (value instanceof RegExp) return new RegExp(value);
  if (value instanceof Date) return new Date(value);
  // 我要判断 value 是对象还是数组 如果是对象 就产生对象 是数组就产生数组
  let obj = new value.constructor();
  for (let key in value) {
    obj[key] = deepClone(value[key]); // 看一看当前的值是不是一个对象
  }
  return obj;
};
export default {
  name: "LargeDataSearchSelect",
  directives: {
    "el-select-loadmore": {
      bind(el, binding) {
        // 获取element-ui定义好的scroll盒子
        const SELECTWRAP_DOM = el.querySelector(
          ".el-select-dropdown .el-select-dropdown__wrap"
        );
        SELECTWRAP_DOM.addEventListener("scroll", function () {
          /**
           * scrollHeight 获取元素内容高度(只读)
           * scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
           * clientHeight 读取元素的可见高度(只读)
           * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
           * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
           */
          const condition =
            this.scrollHeight - this.scrollTop <= this.clientHeight;
          if (condition) binding.value();
        });
      },
    },
  },
  props: {
    selectProps: {
      type: Object,
      default: () => {
        return {
          options: [],
          rangeNumber: 10,
        };
      },
      require: true,
    },
    value: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      selectValue: "",
      rangeNumber: this.selectProps.rangeNumber || 10,
      options: [],
      originalData: [],
    };
  },
  watch: {
    value: {
      handler(newVal) {
        this.selectValue = newVal;
      },
      deep: true,
      immediate: true,
    },
  },
  model: {
    event: "updateChange",
  },
  mounted() {
    this.$nextTick(() => {
      this.originalData = this.options = deepClone(this.selectProps.options);
    });
  },
  methods: {
    loadMore(n) {
      if (n < 8) this.rangeNumber = 10;
      return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数  可自定义
    },
    handleGlobalIdFilter: debounce(function (query) {
      this.selectValue = query;
      if (query) {
        let newOption = this.originalData.filter((item) =>
          item[this.selectProps.label || "label"].includes(query)
        );
        this.options = newOption.length ? newOption : this.originalData
      } else {
        this.options = this.originalData;
      }
    }, 500),
    selectBlur() {
      this.selectValue = this.value
      this.options = this.originalData
    },
    selectChange() {
      this.$emit("updateChange", this.selectValue);
      this.options = this.originalData;
    },
  },
  render() {
    return (
      <el-select
        {...this.$attrs}
        v-model={this.selectValue}
        placeholder={this.selectProps.placeholder || "请选择"}
        clearable
        filterable
        filter-method={this.handleGlobalIdFilter}
        onBlur={this.selectBlur}
        onChange={this.selectChange}
        v-el-select-loadmore:rangeNumber={this.loadMore(this.rangeNumber)}
      >
        {this.options.slice(0, this.rangeNumber).map((item, index) => {
          return (
            <el-option
              key={index}
              label={item[this.selectProps.label || "label"]}
              value={item[this.selectProps.value || "value"]}
            ></el-option>
          );
        })}
      </el-select>
    );
  },
};

控件使用

<template>
  <div class="select">
    <div>可搜索的选择框</div>
    <LargeDataSearchSelect
      v-model="form.data"
      :selectProps.sync="selectProps"
      @updateChange="updateChange"
    />
    <el-button @click="getValue">按钮</el-button>
  </div>
</template>

<script>
import LargeDataSearchSelect from "@/components/LargeDataSearchSelect";
export default {
  name: "SelectView",
  components: { LargeDataSearchSelect },
  data() {
    return {
      form: {
        data: "",
      },
      selectProps: {
        options: [],
        rangeNumber: 10,
        // label: "nihao",
        // value: "nihao",
        // placeholder: "请选择下拉列表",
      },
    };
  },
  mounted() {
    this.getSelectData();
  },
  methods: {
    updateChange() {
      console.log("你好");
    },
    // 生成一万条数据
    getSelectData() {
      let selectData = [];
      for (let i = 0; i < 10000; i++) {
        selectData.push({
          value: `${i}`,
          label: `备选项 ${i}`,
        });
      }
      this.selectProps.options = this.options.concat(selectData);
    },
  },
};
</script>