第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 锁,防止短时间多次触发请求
相关推荐
FungLeo32 分钟前
成为全栈·Vue 管理后台篇·分类树与标签管理:层级数据如何落到管理界面
前端·javascript·vue.js·分类树·naive ui·标签管理·前端数据结构
ruanno_top4 小时前
选中一项后,焦点掉回了页面顶部:三个弹层的焦点还原
vue.js
tryCbest6 小时前
Vue3——第 17 篇:模板引用(ref)与组件实例——操作 DOM 的正确姿势
vue.js·前端搭建
头发还在的女程序员7 小时前
Java在线租房系统源码解析:Spring Boot+Vue 3+UniApp房源管理与预约看房方案
java·vue.js·spring boot·租房小程序·租房系统·租房软件
FYKJ_20107 小时前
springboot同人周边订单管理系统48955-计算机毕业设计、课程设计
java·javascript·vue.js·spring boot·django·php·课程设计
梯度下降者17 小时前
Nuxt框架
vue.js·服务端渲染·全栈开发·混合渲染·nuxt框架
yuyuxun11 天前
协同过滤的校园二手物品智能推荐系统的设计与实现 毕业设计-附源码40082
javascript·vue.js·spring boot·python·数据分析·django·课程设计
FungLeo1 天前
成为全栈·Vue 管理后台篇·编辑器图片上传:从文件选择到文章附件关联
前端·vue.js·编辑器·markdown·文件上传·formdata·附件管理
码云社区1 天前
智慧物业系统选型指南:房屋档案、账单管理与报修协作
前端·javascript·vue.js·智慧物业
ruanno_top2 天前
表单重置后,验证码还显示已通过:Vue 受控组件的 3 种假同步
vue.js