第6节:远程搜索弹窗(remote 模式),弹窗滚动加载分页

第6节:远程搜索弹窗(remote 模式),弹窗滚动加载分页

本节重点:remote 远程搜索,输入关键词请求接口,还有下拉弹窗滚动监听实现分页加载选项。区分【本地过滤 filterable】和【远程搜索 remote】。

核心知识点

  1. remote:开启远程搜索,不再前端本地过滤 ,需要自己在 remote-method 里面请求后端
  2. remote-method:回调函数,参数是用户输入的搜索关键词,输入内容变化就触发
  3. loading:el-select 的 loading 属性,请求接口时显示加载动画
  4. popper 实例获取:拿到弹窗 DOM,监听 scroll 事件,实现滚动到底加载更多

⚠️ 坑点:remote 模式下,必须手动清空选项列表,关键词变化要重置页码

完整可测试代码

复制代码
<template>
  <div class="container">
    <h4>远程搜索下拉,弹窗滚动分页加载</h4>
    <el-select
      v-model="selectVal"
      filterable
      remote
      :remote-method="handleRemoteSearch"
      :loading="loading"
      placeholder="输入关键词远程搜索"
      style="width:320px"
      @visible-change="handleVisibleChange"
    >
      <el-option
        v-for="item in optionList"
        :key="item.id"
        :label="item.name"
        :value="item.id"
      />
    </el-select>
    <p>选中值:{{ selectVal }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const selectVal = ref('')
const loading = ref(false)
const optionList = ref([])
const page = ref(1)
const pageSize = 5
const keyword = ref('')
// popper DOM
let popperDom = null

// 模拟接口请求
const fetchData = async (searchKey, p) => {
  // 模拟网络延迟
  await new Promise(resolve => setTimeout(resolve, 600))
  // 模拟后端返回数据
  const mockArr = []
  for(let i = 1; i <= pageSize; i++){
    const id = (p -1)*pageSize + i
    mockArr.push({
      id,
      name: `${searchKey || '全部'} 选项-${id}`
    })
  }
  return mockArr
}

// 远程搜索触发
const handleRemoteSearch = async (val) => {
  keyword.value = val
  page.value = 1 // 关键词改变,重置页码
  loading.value = true
  const res = await fetchData(val, page.value)
  optionList.value = res
  loading.value = false
}

// 弹窗打开/关闭
const handleVisibleChange = async (isOpen) => {
  if(isOpen){
    // 弹窗打开,等待popper渲染完成,获取弹窗滚动容器
    setTimeout(()=>{
      popperDom = document.querySelector('.el-select__popper .el-scrollbar__wrap')
      if(!popperDom) return
      // 绑定滚动事件
      popperDom.addEventListener('scroll', handlePopperScroll)
    }, 100)
  }else{
    // 弹窗关闭,移除滚动监听,防止多次绑定
    if(popperDom){
      popperDom.removeEventListener('scroll', handlePopperScroll)
      popperDom = null
    }
  }
}

// 弹窗滚动事件
const handlePopperScroll = async () => {
  const { scrollTop, scrollHeight, clientHeight } = popperDom
  // 判断滚动到底部,预留20px容错
  if(scrollTop + clientHeight >= scrollHeight - 20 && !loading.value){
    loading.value = true
    page.value +=1
    const res = await fetchData(keyword.value, page.value)
    // 追加数据
    optionList.value.push(...res)
    loading.value = false
  }
}
</script>

<style scoped>
.container {
  padding:20px;
}
</style>

测试步骤

  1. 输入文字,触发远程搜索,看到 loading 加载动画,列表刷新
  2. 下拉弹窗滚动到底部,自动加载下一页数据,追加到弹窗列表
  3. 修改搜索关键词:页码重置,列表重新请求第一页
  4. 关闭弹窗:滚动事件解绑,避免多次监听内存泄漏

业务坑总结

  1. remote 开启后,原生前端过滤失效,所有过滤逻辑交给后端
  2. visible-change 打开弹窗拿 popper DOM,一定要加 setTimeout,等弹窗 DOM 渲染完成
  3. 弹窗关闭必须 removeEventListener,否则多次打开弹窗会重复绑定滚动事件
  4. 滚动加载要加 loading 锁,防止短时间多次触发请求
相关推荐
用户9177533718752 小时前
从零封装一个地图组件库:OpenLayers + Vue 的工程化实践
vue.js
雪芽蓝域zzs3 小时前
第7节:多选模式、自定义选项渲染、受控弹窗显隐
vue.js·elementui
acd120095 小时前
前端随笔:数据明明变了,Vue 页面就是不更新
前端·javascript·vue.js
vx_Biye_Design5 小时前
springboot一站式旅游管理平台81037-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·课程设计·express·旅游
vx_Biye_Design5 小时前
springboot宠物寄养服务预约与监管系统82684-计算机课程设计、毕业设计
java·vue.js·spring boot·elasticsearch·课程设计·express·宠物
vx_Biye_Design5 小时前
springboot小学生英语学习APP62773-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·学习·课程设计
vx_Biye_Design6 小时前
expressDeepSeek社团咨询助手的学生社团管理系统60746-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·课程设计·express
vx_Biye_Design6 小时前
springboot宠物领养与救助平台64334-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·mysql·课程设计·宠物
vx_Biye_Design6 小时前
django就业信息推荐系统61953-计算机课程设计、毕业设计
java·vue.js·spring boot·python·架构·django·课程设计
羲云6 小时前
给 Vue 页面加个 Markdown 编辑器:ME.js 的接入、图片粘贴与音视频
javascript·vue.js