el-select二次封装,解决数据量太大导致卡顿问题,实现远程搜索,滚动加载数据,搜索数据回显

 

问题描述:

最近项目中,表单中有需要选择公司联系人的下拉框,由于人员过多,选择的时候会因为数据量过大导致页面卡顿,于是对于el-select进行二次封装

解决方案: 

  • remote-method:远程搜索方法
  • visible-change:下拉框出现/隐藏时触发

1、对返回数据进行切割,使用visible-change,在下拉框出现时默认显示100条数据;

2、使用remote-method远程方法进行搜索;

3、搜索时,将已经选择的数据合并到搜索列表中,防止因列表匹配不到显示成ID;

4、创建 el-select-loadmore 指令方法进行滚动加载;

5、使用 @input="$emit('input',$event)" 进行双向绑定

实现方式: 

1、在main.js中创建滚动指令 el-select-loadmore

// 下拉列表
Vue.directive(
  'el-select-loadmore', {
  bind(el, binding) {
    let self = this
    // 获取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()
    });
  }
}
)

2、创建componentPeople.vue组件文件

<template>
  <el-select
    :value="value"
    v-el-select-loadmore:rangeNum="loadMore(rangeNumber)"
    @change="getChange"
    @input="$emit('input',$event)"
    :loading="loading"
    :multiple="multiple"
    reserve-keyword
    clearable
    :disabled="selectDisabled"
    :remote-method="(query) => {remoteMethod(query, value)}"
    filterable
    placeholder="输入姓名进行匹配"
    remote
    :size="selectSize"
    style="width: 100%"
    @visible-change="visibleChange"
  >
    <el-option
      v-for="item in originalOptions.slice(0, rangeNumber)"
      :key="item.userId"
      :label="item.username"
      :value="item.userId"
    />
  </el-select>
</template>

<script>
export default {
  name: "componentPeople",
  props: {
    //组件size
    selectSize: {
      type: String,
      default: 'medium'
    },
    //组件options
    options: {
      type: Array,
      default: () => {
        return []
      }
    },
    //传入的数据
    value: {
      type: [String, Number, Array],
    },
    //是否多选
    multiple: {
      type: Boolean,
      default: false
    },
    //是否禁用
    selectDisabled: {
      type: Boolean,
      default: false
    }
  },
  //使用监听器监听传入的options,赋值给originalOptions
  watch: {
    options: {
      handler(val) {
        console.log(val);
        this.originalOptions = val
      },
      deep: true
    },
    //监听所选项变化,进行搜索回显/或初始化列表数据并回显
    value(val) {
      this.remoteMethod(this.text,val)
    },
  },
  data() {
    return{
      text: '', //默认搜索项
      loading: false, //搜索loading
      rangeNumber: 100, //默认显示列表数量
      originalOptions: [],//下拉列表数据
    }
  },
  methods: {
    // 下拉框显示/隐藏触发,下来框显示初始话值为100
    visibleChange(flag) {
      if (flag) {
        this.rangeNumber = 100
      }
    },
    //远程搜索方法
    remoteMethod(query, checkedData) {
      this.text = query
      this.loading = true;
      setTimeout(() => {
        this.loading = false;
        //从完整数据中筛选所匹配项
        let arr = this.options.filter(item => {
          return item.username.toLowerCase().indexOf(query.toLowerCase()) > -1;
        });
        //获取已经选择的数据防止因数据初始化匹配不到显示为ID
        let initUserList = !!checkedData ? this.initUserSelectData(checkedData) : []
        //删除搜索列表相同ID,并重新赋值
        this.originalOptions = [...initUserList, ...arr.filter(item => !initUserList.some(x => x.userId === item.userId ))]
      }, 80);
    },
    // 解决回显时显示为id的问题
    initUserSelectData(arr) {
      //获取当前所选值
      if (this.multiple) {
        return this.options.filter(item => arr.some(x => x === item.userId)); // 选中的值 数组
      }
      return this.options.filter(item => arr === item.userId); // 选中的值 数组
    },
    // 下拉框滚动触发添加待选数据
    loadMore(n) {
      //n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
      return () => this.rangeNumber += 10 //每次滚动到底部可以新增条数  可自定义
    },
    getChange(val) {
      this.$emit('getChange', val)
    },
  },
  mounted() {
    this.originalOptions = this.options
  }
}
</script>

<style scoped>

</style>

3、在页面中使用

<component-people v-model="formDta.name" :options="options" selectSize="mini" :multiple="true" ></component-people>

 

完结撒花0.0. 

 

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值