el-select下拉滚动加载更多封装成组件

el-select下拉滚动加载更多封装成组件 — vue技术交流群(864583465)

前言:该组件基于typescript 和vue2的class写法,组件代码如下:


<template>
  <el-select
    size="mini"
    v-model="value"
    filterable
    :multiple="multiple"
    :clearable="clearable"
    :allow-create="allowCreate"
    @change="selectChanged"
    @clear="selectChanged"
    v-el-select-loadmore="loadMore(rangeNumber)"
    :filter-method="filterMethod"
    value-key="index"
    :placeholder="placeholder">
    <el-option
      v-for="item in searchedOption.slice(0, rangeNumber)"
      :key="item.index"
      :label="item[labelValueObj.label]"
      :value="item[labelValueObj.value]"/>
  </el-select>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
import { PropType } from 'vue';

@Component({
  directives: {
    'el-select-loadmore':(el, binding) => {
      // 获取element-ui定义好的scroll盒子
      const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
      if(SELECTWRAP_DOM){
        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 + 10;
          if (condition) binding.value();
        });
      }
    },
  }
})
export default class extends Vue {
  @Prop({ type: String, default: '' }) placeholder
  @Prop({ type: Boolean, default: false }) clearable
  @Prop({ type: Boolean, default: false }) allowCreate
  @Prop({ type: Boolean, default: false }) multiple
  @Prop() selectValue
  @Prop({ type: Array, default: () => [] }) options
  @Prop({ type: Object as PropType<{ label: string, value: string }>, default: () => {} }) labelValueObj
  @Prop({ type: Array as PropType<string[]>, default: '' }) searchMatchFields // 搜索时需要匹配的字段
  private rangeNumber: number = 10
  private searchedOption = []
  private value: string | number | string[] | number[] = ''



  @Watch('multiple', { immediate: true })
  multipleChanged(val){
    if(val){
      this.value = []
    }
  }

  @Watch('selectValue')
  selectValueChanged(val){
    this.value = val
  }
  get optionsStr(){
    return JSON.stringify(this.options)
  }
  @Watch('optionsStr', { immediate: true })
  optionsChanged(){
    this.searchedOption = this.options.map((item, index) => {
      return {
        ...item,
        index: index
      }
    })
  }

  selectChanged(val){
    this.$emit('update:selectValue', val)
  }

  loadMore(n) {
    console.log('loadMore:' + n, this.rangeNumber)
    // n是默认初始展示的条数会在渲染的时候就可以获取,具体可以打log查看
    // elementui下拉超过7条才会出滚动条,如果初始不出滚动条无法触发loadMore方法
    return () => (this.rangeNumber += 5); // 每次滚动到底部可以新增条数  可自定义
  }
  filterMethod(query = ''){
    try {
      console.log('query:' + query)
      this.rangeNumber = 10
      if(this.searchMatchFields.length === 0){
        this.searchedOption = this.options.slice(0)
      } else {
        this.searchedOption = this.options.filter(item => {
          return this.fmtFilterCondition(item, query)
        })
      }
    } catch (e) {
      console.log(e)
    }
  }
  fmtFilterCondition(item, query){
    for (let field of this.searchMatchFields) {
      if(item[field] !== undefined && item[field] !== null && item[field].includes(query)){
        return true
      }
    }
    return false
  }


}
</script>


如何调用代码如下:

<template>
	<div>
		<div>当前选择值:{{ userId }}</div>
        <select-load-more
          placeholder="请选择用户或输入用户姓名或用户id"
          :clearable="true"
          :select-value.sync="userId"
          :options="userList"
          :label-value-obj="{ label: 'name', value: 'id' }"
          :search-match-fields="['name', 'id']"
        />
	</div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'


@Component({
  components: {
    'select-load-more': () => import('组件位置/el-select-scroll-load-more.vue')
  }
})
export default class extends Vue {
  private userId: string = ''
  private userList = [
    {
      id: 1,
      name: '张三',
      age: 20,
      sex: '男'
    },
    {
      id: 2,
      name: '张三2',
      age: 20,
      sex: '男'
    },
    {
      id: 3,
      name: '张三3',
      age: 20,
      sex: '男'
    },
    {
      id: 4,
      name: '张三4',
      age: 20,
      sex: '男'
    }
  ]
}

好的,以下是一个简单的实现代码,您可以参考一下: ```vue <template> <div> <el-select v-model="selected" filterable @change="handleSelectChange" remote :remote-method="remoteMethod"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> <el-pagination :current-page.sync="currentPage" :page-size="pageSize" :total="total" @current-change="handlePageChange" /> </div> </template> <script> export default { data() { return { selected: '', options: [], currentPage: 1, pageSize: 10, total: 0 } }, methods: { // 远程搜索方法 remoteMethod(query) { // 发送请求获取对应的数据 axios.get('/api/options', { params: { query, page: this.currentPage, pageSize: this.pageSize } }).then(response => { const { data, total } = response.data this.options = data this.total = total }).catch(error => { console.log(error) }) }, // 选择发生变化 handleSelectChange() { console.log(this.selected) }, // 分页发生变化 handlePageChange(current) { this.currentPage = current this.remoteMethod('') } } } </script> ``` 在这个代码中,我们使用了 Element UI 中的 el-selectel-pagination 组件来实现分页下拉框。我们通过 el-select 的 filterable 属性来开启模糊搜索功能,通过 remote 属性来开启远程搜索功能。我们使用了 axios 发送异步请求来获取后端返回的数据,并将数据渲染到 el-select 中。我们使用 el-pagination 组件来实现分页功能,当用户选择不同的页码时,我们会发送请求获取对应的数据,再将数据渲染到 el-select 中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值