vue3 elementPlus select选择器下拉加载更多

选择器下拉实现分页加载

1、使用Infinite Scroll 无限滚动  v-infinite-scroll

selectLoadMore.vue

<template>
  <el-select
    style="width: 100%"
    v-if="isMounted"
    v-model="_modelValue"
    remote
    reserve-keyword
    @visible-change="handleVisibleChange"
    @change="handelChange"
    :remote-method="remoteMethod"
    filterable
    :loading="loading"
    clearable
    :multiple="multiple"
    :disabled="disabled"
    :placeholder="placeholder">
    <div
      v-infinite-scroll="loadMore"
      :infinite-scroll-delay="500"
      style="overflow-y: hidden">
      <el-option
        v-for="item in optionsList"
        :key="item[optionName.value]"
        :label="item[optionName.label]"
        :value="item[optionName.value]" />
    </div>
  </el-select>
</template>

<script setup>
const { proxy } = getCurrentInstance();
//selectLoadMoreDefault 为分页参数
const { selectLoadMoreDefault } = proxy.constants;
const props = defineProps({
  options: {
    type: Array
  },
  modelValue: {
    type: [String, Number]
  },
  optionsName: {
    type: Object,
    default: () => ({})
  },
  total: {
    type: Number,
    default: 0
  },
  pageSize: {
    type: Number,
    default: 0
  },
  pageNum: {
    type: Number,
    default: 0
  },
  getList: {
    type: Function
  },
  placeholder: {
    type: String,
    default: '请输入/选择'
  },
  disabled: {
    type: Boolean,
    default: false
  },
  multiple: {
    type: Boolean,
    default: false
  },
  clearable: {
    type: Boolean,
    default: true
  },
  // 除分页参数的其他参数
  otherParams: {
    type: Object,
    default: () => ({})
  }
});
const emits = defineEmits(['changeData', 'update:modelValue']);
const pageSize = computed(
  () => props.pageSize || selectLoadMoreDefault.pageSize
);
const pageNum = computed(() => props.pageNum || selectLoadMoreDefault.pageNum);
const queryParams = ref({
  pageSize: pageSize.value,
  pageNum: pageNum.value,
  name: ''
});
const visible = ref(false);
const _modelValue = ref(props.modelValue);
watch(
  () => [props.modelValue, props.total],
  (val) => {
    _modelValue.value = val[0];
    emits('update:modelValue', val[0]);
    if (!val[1]) {
      queryParams.value.pageNum = 1;
    }
  }
);
const loading = ref(false);
const isMounted = ref(false);
const optionsList = computed(() => props.options);
onMounted(() => {
  isMounted.value = true;
});
// 下拉选属性配置
const optionName = computed(() => {
  return {
    label: props.optionsName?.label ?? 'label',
    value: props.optionsName?.value ?? 'value'
  };
});

const handelChange = (val) => {
  emits('changeData', val);
  emits('update:modelValue', val);
};
const loadMore = () => {
  let sum = queryParams.value.pageNum * queryParams.value.pageSize;
  if (sum >= props.total) return;
  visible.value && remoteMethod(queryParams.value.name, false);
};
const remoteMethod = (query, isEmpty = true) => {
  // debugger;
  if (visible.value) {
    queryParams.value.name = query;
    // if (query || !isEmpty) {
    queryParams.value.pageNum = isEmpty ? 1 : queryParams.value.pageNum + 1;
    // loading.value = true;
    setTimeout(() => {
      // loading.value = false;
      props.getList({ ...queryParams.value, ...props.otherParams }, isEmpty);
    }, 200);
    // }
  }
};
// 控制下拉框的显示隐藏
const handleVisibleChange = (isVisible) => {
  visible.value = isVisible;
};
</script>

2、自定义指令(推荐)

<template>
  <!-- 
    popper-class="single-select-loadmore" -->
  <el-select
    style="width: 100%"
    v-if="isMounted"
    v-model="_modelValue"
    remote
    reserve-keyword
    @visible-change="handleVisibleChange"
    @change="handelChange"
    :remote-method="remoteMethod"
    filterable
    :loading="loading"
    clearable
    v-loadMore="loadMore"
    :multiple="multiple"
    :disabled="disabled"
    :placeholder="placeholder"
    :teleported="false">
    <el-option
      v-for="item in optionsList"
      :key="item[optionName.value]"
      :label="item[optionName.label]"
      :value="item[optionName.value]" />
  </el-select>
</template>

<script setup>
const { proxy } = getCurrentInstance();
const { selectLoadMoreDefault } = proxy.constants;
const props = defineProps({
  options: {
    type: Array
  },
  modelValue: {
    type: [String, Number]
  },
  optionsName: {
    type: Object,
    default: () => ({})
  },
  total: {
    type: Number,
    default: 0
  },
  pageSize: {
    type: Number,
    default: 0
  },
  pageNum: {
    type: Number,
    default: 0
  },
  getList: {
    type: Function
  },
  placeholder: {
    type: String,
    default: '请输入/选择'
  },
  disabled: {
    type: Boolean,
    default: false
  },
  multiple: {
    type: Boolean,
    default: false
  },
  clearable: {
    type: Boolean,
    default: true
  },
  // 除分页参数的其他参数
  otherParams: {
    type: Object,
    default: () => ({})
  }
});
const emits = defineEmits(['changeData', 'update:modelValue']);
const pageSize = computed(
  () => props.pageSize || selectLoadMoreDefault.pageSize
);
const pageNum = computed(() => props.pageNum || selectLoadMoreDefault.pageNum);
const queryParams = ref({
  pageSize: pageSize.value,
  pageNum: pageNum.value,
  name: ''
});
const visible = ref(false);
const _modelValue = ref(props.modelValue);
watch(
  () => [props.modelValue, props.total],
  (val) => {
    _modelValue.value = val[0];
    emits('update:modelValue', val[0]);
    if (!val[1]) {
      queryParams.value.pageNum = 1;
    }
  }
);
const loading = ref(false);
const isMounted = ref(false);
const optionsList = computed(() => props.options);
onMounted(() => {
  isMounted.value = true;
});
onUnmounted(() => {
  isMounted.value = false;
});
// 下拉选属性配置
const optionName = computed(() => {
  return {
    label: props.optionsName?.label ?? 'label',
    value: props.optionsName?.value ?? 'value'
  };
});

const handelChange = (val) => {
  emits('changeData', val);
  emits('update:modelValue', val);
};
const loadMore = () => {
  // debugger;
  let sum = queryParams.value.pageNum * queryParams.value.pageSize;
  if (sum >= props.total) return;
  visible.value && remoteMethod(queryParams.value.name, false);
};
const remoteMethod = (query, isEmpty = true) => {
  // debugger;
  if (visible.value) {
    queryParams.value.name = query;
    // if (query || !isEmpty) {
    queryParams.value.pageNum = isEmpty ? 1 : queryParams.value.pageNum + 1;
    // loading.value = true;
    setTimeout(() => {
      // loading.value = false;
      props.getList({ ...queryParams.value, ...props.otherParams }, isEmpty);
    }, 200);
    // }
  }
};
// 控制下拉框的显示隐藏
const handleVisibleChange = (isVisible) => {
  visible.value = isVisible;
};
</script>

loadmore.js

import { nextTick } from 'vue';
const Loadmore = {
    mounted(el, binding) {
        nextTick(() => {
            // teleported为true 需添加popper-class .single-select-loadmore
            const domClass = '.el-select-dropdown__wrap';
            const element = el.querySelector(domClass);

            let handleScroll = () => {
                const { scrollTop, scrollHeight, clientHeight } = element;
                const scrollDistance = scrollHeight - scrollTop <= clientHeight;
                if (scrollDistance) {
                    binding.value(); // 调用加载更多的回调函数
                }
            };
            // 将事件处理函数存储在元素的某个属性上以便后续引用
            element.__vueCustomEvent__ = handleScroll;
            // 监听滚动事件
            element && element.addEventListener('scroll', handleScroll);
        });
    },
    beforeUnmount(el) {
        // 从元素上获取滚动事件并移除监听器
        const domClass = '.el-select-dropdown__wrap';
        const element = el.querySelector(domClass);
        if (element.__vueCustomEvent__) {
            element.removeEventListener('scroll', element.__vueCustomEvent__);
            // 可选:删除存储的函数引用以避免内存泄漏
            delete element.__vueCustomEvent__;
        }
    }
};
export default Loadmore;

使用


<select-loadmore
            v-model="form.id"
            :get-list="handlesSelect"
            placeholder="请输入/选择"
            @change-data="changeAddMember"
            :other-params="{
              // deptId: quest_deptId,
            }"
            :options="drugList"
            :options-name="{ label: 'text', value: 'drugId' }"
            :total="drugTotal" />


const handlesSelectDrug = (query, isEmpty) => {
  let newQuery = JSON.parse(JSON.stringify(query));
  if (newQuery.isEmpty) {
    delete newQuery.isEmpty;
  }
  if (newQuery.name) {
    newQuery.chemicalName = newQuery.name;
    delete newQuery.name;
  }
  listDrug(newQuery).then((response) => {
    let list = response.rows;
    list.value = isEmpty
      ? response.rows
      : [...list.value, ...response.rows];
    total.value = response.total;
  });
};





  handlesSelectDrug({ ...selectLoadMoreDefault }, false);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值