el-select滚动获取下拉数据;el-select滚动加载

el-select下拉获取数据

1.解决问题

场景:下拉数据量过大,后端提供一个分页查询接口;需要每次滚动加载下一页的下拉数据

且单选的状态,需要支持回显,通过name名称查询回显;--本文已包含

如果是多选回显,可以让后端提供一个根据idList能反向找到对应id的下拉集合的接口;--可自己试试

2.封装MyScrollSelect组件

javascript 复制代码
<template>
  <div>list长度:{{ list.length }}</div>
  <div>$attrs:{{ $attrs }}</div>
  <el-select @change="changeVal" v-bind="$attrs" :remote-method="remoteMethod" style="width: 100%">
    <div v-infinite-scroll="loadMore" style="overflow: hidden">
      <el-option v-for="item in list" :key="item[valueKey]" :label="item[labelKey]" :value="item[valueKey]" />
      <!-- 下拉底部加载提示 -->
      <div v-if="loading" class="loading-text">加载中...</div>
    </div>
  </el-select>
</template>

<script setup >
import { ref, watch, onMounted } from "vue"
import { debounce } from "lodash"

const emit = defineEmits(['update:searchName']);

const props = defineProps({
  // v-model绑定值不为空时传递初始数据列表
  initialOptions: {
    type: Array,
    default: () => []
  },
  // 传入对应的列表加载api
  methods: {
    type: Function,
    required: true // 或者 true,取决于它是否必须被传递
  },
  // 传入查询关键字
  searchKey: {
    type: String,
    default: ""
  },
  // 所选key对用name
  searchName: {
    type: String,
    default: undefined
  },
  labelKey: {
    type: String,
    default: "name"
  },
  valueKey: {
    type: String,
    default: "id"
  },
  // 查询的其他参数
  queryData: {
    type: Object,
    default: () => { }
  },
})

const isMounted = ref(false)
const loading = ref(false)

const list = ref([]) // 选项列表
const queryFrom = ref({
  pageNum: 1,
  totalPage: 1,
  pageSize: 20
})

// 自定义远程搜索方法
const remoteMethod = (query) => {
  queryFrom.value.pageNum = 1
  list.value = []
  queryFrom.value[props.searchKey] = query
  queryFrom.value = { ...queryFrom.value, ...props.queryData }
  getList()
}

// 调用props.methods获取下拉数据
const getList = () => {
  loading.value = true
  props.methods(queryFrom.value).then(res => {
    console.log('%c【' + 'res' + '】打印', 'color:#fff;background:#0f0', res)
    list.value = [...list.value, ...res.records]
    queryFrom.value.totalPage = Math.ceil(res.total / 20) // 计算总页数 不是总数
  }).finally(() => {
    loading.value = false
  })
}

// 无限滚动触底加载
const loadMore = debounce(() => {
  if (queryFrom.value.pageNum >= queryFrom.value.totalPage || loading.value) return
  queryFrom.value.pageNum++
  getList()
}, 200)

// 根据id回显name
const changeVal = (e) => {
  list.value.forEach(ele => {
    if (ele[props.valueKey] === e) {
      emit('update:searchName', ele[props.labelKey])
    }
  })
}

// 监听 initialOptions 的变化,用于加载初始值
watch(
  () => props.initialOptions,
  newVal => {
    // 如果 modelValue 中的值还未加载到选项中,加载这些数据
    if (newVal && newVal.length > 0) {
      list.value.push(...props.initialOptions)
    }
  },
  { immediate: true }
)

onMounted(() => {
  isMounted.value = true
  // 获取初始数据

  if (props.searchName) {
    remoteMethod(props.searchName) // 根据name回显
  } else {
    getList()
  }
})
</script>
<style scoped>
.loading-text {
  padding: 5px;
  text-align: center;
  color: #999;
  font-size: 12px;
}
</style>

3.使用MyScrollSelect组件

javascript 复制代码
<template>
  <div class="page-view wbg pall">
    <pre>{{ form }}</pre>

    <div style="margin-top: 50px">多选:只能存id</div>
    <MyScrollSelect
      v-if="isMounted"
      ref="reviewStageRef"
      v-model="form.idList1"
      :placeholder="'滚动加载或搜索-单选'"
      clearable
      filterable
      remote
      collapse-tags
      collapse-tags-tooltip
      multiple
      :initialOptions="initialOptions"
      :methods="getDeviceNameListApi"
      searchKey="terminalDeviceName"
      valueKey="id"
      labelKey="terminalDeviceName"
    />

    <div style="margin-top: 50px">单选:可存id和name 根据name可回显</div>
    <MyScrollSelect
      v-if="isMounted"
      ref="reviewStageRef"
      v-model="form.terminalDeviceId"
      v-model:searchName="form.terminalDeviceName"
      :placeholder="'滚动加载或搜索-单选'"
      clearable
      filterable
      remote
      :initialOptions="initialOptions"
      :methods="getDeviceNameListApi"
      searchKey="terminalDeviceName"
      valueKey="id"
      labelKey="terminalDeviceName"
    />
  </div>
</template>

<script setup>
import { onMounted, ref } from 'vue'
import { getDeviceNameListApi } from "@/api/ipManagement.js" // 后端获取下拉分页接口

defineOptions({
  name: 'FactorySiteAddressLedger'
})

const isMounted = ref(false)
const form = ref({
  idList1: [], // 多选参数

  terminalDeviceId: '710241160000004443', // 单选参数
  terminalDeviceName: '益海电厂网监工作站',
})

const reviewStageRef = ref(null)

const initialOptions = ref([]) // 初始下拉数据

onMounted(() => {
  isMounted.value = true
})
</script>
<style lang="scss" scoped></style>