ant design vue中select选择框数据较多时容易造成卡顿。解决方法如下面组件所示:

<template>
  <a-select
    allowClear
    @blur="onBlur"
    mode="multiple"
    style="width: 100%"
    v-model="selectId"
    @search="handleSearch"
    @change="handleChange"
    :autoClearSearchValue="false"
    :dropdownMatchSelectWidth="false"
    :filter-option="filterOption"
    @popupScroll="handlePopupScroll"
  >
    <a-select-option v-for="item in partList" :key="item.id">
      {{ item.resName }}
    </a-select-option>
  </a-select>
</template>

<script>

export default {
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    value: {
      type: Array,
      default: () => [],
    },
    selectList: {
      type: Array,
      default: [],
    },
  },
  data() {
    return {
      selectId: [],
      partList:[],
      scrollPage: 1,
      pageSize: 100,
      keyWords: null,
      timer: null,
    }
  },
  mounted() {
    this.loadOption()
  },
  watch: {
    value(val) {
      if (val) {
        this.selectId = val
      } else {
        this.selectId = []
      }
    }
  },
  methods: {
    handlePopupScroll(e) {
      // e.persist()
      const { target } = e
      // scrollHeight:代表包括当前不可见部分的元素的高度
      // scrollTop:代表当有滚动条时滚动条向下滚动的距离,也就是元素顶部被遮住的高度
      // clientHeight:包括padding但不包括border、水平滚动条、margin的元素的高度
      const rmHeight = target.scrollHeight - target.scrollTop
      const clHeight = target.clientHeight
      // 当下拉框失焦的时候,也就是不下拉的时候
      if (rmHeight === 0 && clHeight === 0) {
        this.scrollPage = 1
      } else {
        // 当下拉框下拉并且滚动条到达底部的时候
        // 可以看成是分页,当滚动到底部的时候就翻到下一页
        if (rmHeight < clHeight + 5) {
          const scrollPage = this.scrollPage
          this.scrollPage = scrollPage + 1
          //调用处理数据的函数增加下一页的数据
          this.loadOption(scrollPage + 1)
        }
      }
    },
    loadOption(pageIndex) {
      let data = this.selectList
      const { pageSize, keyWords } = this
      // 通过每页的数据条数和页数得到总的需要展示的数据条数
      const newPageSize = pageSize * (pageIndex || 1)
      let newOptionsData = [],
        len // len 能展示的数据的最大条数
      if (data.length > newPageSize) {
        // 如果总数据的条数大于需要展示的数据
        len = newPageSize
      } else {
        // 否则
        len = data.length
      }
      // 如果有搜索的话,就走这里
      if (!!keyWords) {
        let data_ = data.filter((item) => item.resName.indexOf(keyWords) > -1) || []
        data_.forEach((item, index) => {
          if (index < len) {
            newOptionsData.push(item)
          }
        })
      } else {
        data.forEach((item, index) => {
          if (index < len) {
            newOptionsData.push(item)
          }
        })
      }
      // this.partList = newOptionsData
      this.partList = Array.from(new Set(newOptionsData))
    },
    handleSearch(val) {
      if (!this.timer) {
        const that = this
        this.timer = setTimeout(function () {
          that.searchValue(val)
          that.timer = null
        }, 100)
      }
      this.keyWords = val
    },
    searchValue(value) {
      let data = this.selectList
      let data_ = data.filter((item) => item.resName.indexOf(value) > -1)
      if (data_.length > 100 || value === '') {
        data_ = data_.slice(0, 100)
      }
      // this.partList = data_
      this.partList = Array.from(new Set(data_))
    },
    handleChange(val) {
      this.$emit('change', val)
    },
    onBlur() {
      this.scrollPage = 1
      this.keyWords = null
      this.loadOption()
    },
    filterOption(input, option) {
      return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
    },
  },
}
</script>

<style>
</style>

 

Logo

前往低代码交流专区

更多推荐