el-select下拉框使用 v-infinite-scroll第一次不成功

文章讨论了一个在Vue项目中遇到的问题,即el-select组件的下拉选项需要实现无限滚动功能。问题在于不同项目中同一段代码表现不一致,有的能直接工作,有的则需失去焦点后重试。解决方案是利用visible-change事件,在下拉框显示时同时启用无限滚动区域。代码示例展示了如何结合v-infinite-scroll指令实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:点击el-select之后,出现的下拉框可以请求数据无限滚动,很奇怪的一点是,不同项目的同一个代码,点击下拉框之后,有的可以直接无限滚动,有的第一次不成功,失去焦点之后重新点就有效果了。

解决方法,使用visible-change,当下拉框显示的时候,同时显示无限滚动区域

<template>
  <div style="width: 100%">
    <el-select
      v-if="isMounted"
      v-model="list"
      style="width: 100%"
      filterable
      remote
      clearable
      reserve-keyword
      remote-show-suffix
      :placeholder="placeholder"
      :remote-method="remoteMethod"
      :class="!list ? 'select-avatar' : !showAvatar ? 'select-avatar' : ''"
      @change="onSelectChange"
      @clear="onClearEvent"
      @visible-change="
        (e) => {
          vis = e
        }
      "
    >
      <template #prefix>
        <span v-if="showAvatar && list" class="select-avatar-img">
          <img :src="avatar || ''" />
        </span>
      </template>
      <div v-if="vis" v-infinite-scroll="onScrollEvent" style="height: 200px; overflow: auto">
        <el-option v-for="item in options" :key="item.id" :label="item.userName" :value="item.userId"> {{ item.userName }}-{{ item.policeNo }} </el-option>
      </div>
    </el-select>
  </div>
</template>

isMounted 最好带上,在onMounted的时候为true

vis 这个在visible-change调用之后为true,把v-infinite-scroll="onScrollEvent" 所在的dom显示出来

### 实现 Vue 3 中 Element Plus `el-select` 组件的懒加载 为了实现在 Vue 3 中对 Element Plus 的 `el-select` 组件进行懒加载,可以采用监听下拉列表滚动事件的方法来检测是否接近底部并触发新的数据请求。考虑到新版本中的 `<teleport>` 使用情况以及生命周期的变化,解决方案如下: #### 解决方案概述 通过自定义指令绑定到 `el-select-dropdown` 上,用于监控其内部容器的滚动位置。当滚动至一定阈值时发起网络请求获取额外的数据项。 对于因 `<teleport>` 导致的传统 DOM 查询方式失效的问题,应当利用现代 JavaScript 提供的 API 如 `IntersectionObserver` 或者直接操作文档对象模型 (Document Object Model),即使用 `document.querySelector()` 来定位目标节点[^1]。 针对 vue 生命周期改变引起的问题,在 setup 函数内注册钩子函数,并确保在组件卸载前移除任何已添加的事件监听器以防止内存泄漏[^2]。 下面是一个具体的例子说明如何实现这一特性: ```javascript // 定义一个名为 'infiniteScroll' 的自定义指令 import { onMounted, onUnmounted } from "vue"; export default { mounted(el, binding) { const handleScroll = () => { let scrollTop = el.scrollTop; let scrollHeight = el.scrollHeight; let clientHeight = el.clientHeight; if ((scrollTop + clientHeight >= scrollHeight - 50)) { typeof binding.value === 'function' && binding.value(); } }; el.addEventListener('scroll', handleScroll); // 清理工作 onUnmounted(() => { el.removeEventListener('scroll', handleScroll); }); }, }; ``` 接着修改模板部分以便应用此指令: ```html <template> <!-- ... --> <el-select v-model="value" placeholder="请选择"> <el-option-group v-for="(group, index) in options" :key="index" :label="group.label"> <el-option v-for="item in group.options" :key="item.value" :label="item.label" :value="item.value"/> </el-option-group> <!-- 添加无限滚动区域 --> <div ref="loadMoreRef" class="loading-more" infinite-scroll @infinite-scroll="fetchData"></div> </el-select> </template> ``` 注意这里引入了一个特殊的 div 元素作为占位符,并为其指定了样式 `.loading-more` 和属性 `ref="loadMoreRef"` ,这有助于后续访问该元素实例;同时给它绑定了之前创建好的 `infinite-scroll` 自定义指令。 最后一步是在脚本标签里完成逻辑处理: ```javascript <script lang="ts"> import { defineComponent, reactive, toRefs, watchEffect } from 'vue'; import axios from 'axios'; interface OptionType { label: string, value: number | string } const fetchData = async function() { try { const response = await axios.get('/api/moreOptions'); state.loading = false; state.total += response.data.length; state.groups[state.groups.length - 1].options.push(...response.data.map(item => ({ label: item.name, value: item.id }))); } catch(error){ console.error("Failed to fetch more data", error); } }; let initialLoadDone = false; return defineComponent({ name: "LazySelect", props: {}, setup(props) { const state = reactive<{ loading:boolean, total:number, groups:Array<{label:string,options:Array<OptionType>}> }>({ loading:true, total:0, groups:[{label:'Group One',options:[]}] }); watchEffect(async ()=>{ !initialLoadDone && ( await fetchData(), initialLoadDone=true ); }) return {...toRefs(state), fetchData} } }); </script> ``` 上述代码片段展示了如何设置初始加载过程,并且每当用户滚动到达指定条件时调用 `fetchData` 方法追加更多选项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值