当前位置: 首页 > 工具软件 > v-selectpage > 使用案例 >

el-select进行二次封装,支持远程搜索remote-method+滚动加载el-select-loadmore。可结合使用

宰子琪
2023-12-01

使用场景:

类似:表单中有需要选择的下拉框选项太多,选择的时候会因为数据量过大导致页面卡顿,于是对于el-select进行二次封装

解决方案:

  • remote-method:远程搜索方法
  • 创建 el-select-loadmore 指令方法进行滚动加载

组件代码:

value:数据绑定传入的数据
options:选项数据,必填

@visibleChange 下拉框出现/隐藏时触发
@loadMore 滚动加载触发
@remoteMethod 远程搜索触发
@change 选中值发生变化时触发

<template>
    <YSelect v-model="form.id" :options="list" :loading="loading" :placeholder="'请选择xxx'" @visibleChange="visibleChange" @loadMore="loadMore" @remoteMethod="remoteMethod" @change="change" />
</template>


<script>
import YSelect from '@/components/ySelect'
export default {
    components: { YSelect },
    data: {
        return {
            form: {
                id: ''
            },
            selectForm: {
                page: 1,
                size: 100,
                name: ''
            },
            loading: false
        }
    },
    methods: {
        init: async function() {
            this.loading = true
            // 获取选项数据,后端需支持 page  size  name搜索
            const res = await getIdOptions({page: this.selectForm.page, size: this.selectForm.size, name: this.select.name})
            this.list = res.data
            this.loading = false
        },
        change(value) {
            
        },
        visibleChange(status) {
            this.select.name = ''
        },
        loadMore(page) {
            this.selectForm.page = page
            this.init()
        },
        remoteMethod(query, page) {
            this.selectForm.page = page
            this.select.name = query
            this.init()
        }
    }
}
</script>

组件代码:

<template>
  <div>
    <el-select
      v-el-select-loadmore="loadMore"
      :value="value"
      :loading="loading"
      :multiple="multiple"
      :placeholder="placeholder"
      filterable
      remote
      :remote-method="(query) => {remoteMethod(query, value)}"
      style="width: 100%;"
      @change="change"
      @input="$emit('input',$event)"
      @visible-change="visibleChange"
    >
      <el-option v-if="hasAll" :label="defaultLabel" value="" />
      <el-option
        v-for="item in optionsList"
        :key="item.id"
        :label="item.name"
        :value="item.id"
      />
    </el-select>
  </div>
</template>

<script>
export default {
  name: 'YSelect',
  directives: {
    'el-select-loadmore': {
      bind(el, binding) {
        // 获取element-ui定义好的scroll盒子
        const DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
        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: {
    // 传入的数据,必填
    value: {
      type: [String, Number, Array],
      default: null
    },
    // 选项数据,必填
    options: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 是否有全部选项
    hasAll: {
      type: Boolean,
      default: true
    },
    defaultLabel: {
      type: String,
      default: '全部'
    },
    // 加载loading
    loading: {
      type: Boolean,
      default: false
    },
    // 提示
    placeholder: {
      type: String,
      default: '请选择'
    },
    // 是否支持多选
    multiple: {
      type: Boolean,
      default: false
    },
    // 每次显示数量
    size: {
      type: Number,
      default: 100
    }
  },
  data() {
    return {
      page: 1,
      pageRemote: 1,
      defaultLoading: false,
      timer: null,
      optionsList: [],
      oldOptions: [],
      isRemote: false
    }
  },
  watch: {
    options: {
      handler(val) {
        if (this.isRemote) {
          if (val) {
            this.optionsList = val
            this.oldOptions = this.oldOptions.filter((item) => {
              return !val.some(valItem => item.id === valItem.id)
            })
            this.oldOptions = [...this.oldOptions, ...val]
          }
        } else {
          if (val) {
            this.optionsList = this.optionsList.filter((item) => {
              return !val.some(valItem => item.id === valItem.id)
            })
            this.optionsList = [...this.optionsList, ...val]
          }
        }
      },
      deep: true
    }
  },
  mounted() {
    this.optionsList = this.options
  },
  methods: {
    change(val) {
      this.$emit('change', val)
    },
    visibleChange(status) {
      if (!status) {
        if (this.isRemote) {
          this.isRemote = false
          this.optionsList = [...this.oldOptions]
        }
      }
      this.$emit('visibleChange', status)
    },
    loadMore() {
      console.log(this.isRemote, this.pageRemote, this.page)
      if (this.isRemote) {
        if (this.pageRemote === 1) {
          this.$emit('loadMore', this.pageRemote)
          this.pageRemote++
        } else {
          this.pageRemote++
          this.$emit('loadMore', this.pageRemote)
        }
      } else {
        this.page++
        this.$emit('loadMore', this.page)
      }
    },
    remoteMethod(query) {
      this.pageRemote = 1
      if (this.timer) {
        clearTimeout(this.timer)
        this.timer = null
      }
      this.timer = setTimeout(() => {
        this.isRemote = true
        this.oldOptions = [...this.optionsList]
        this.optionsList = []
        this.$emit('remoteMethod', query, this.pageRemote)
      }, 500)
    }
  }
}
</script>

<style lang='scss' scoped>

</style>
 类似资料: