关于下拉框动态加载数据库数据的解决方案

问题描述

今天遇到一个需求,需要通过一个下拉框选择工作单位/高校,且支持模糊搜索。

数据库中有2820条数据,如果从下拉框中一次性查出2820条数据,必然可能遇到查询时间过久导致页面卡顿的问题,极大的影响用户体验。

解决方案

于是我思考良久,决定做一个动态加载数据的下拉框。

首先,后端提供一个分页查询的接口,通过设置pageNumpageSize动态控制每次查询多少条数据显示。分页接口这里不做过多阐述,相信大家都会。

重点来了

因为我们需要从下拉框中动态加载远程数据库数据,因此我们可以通过监听滚轮事件来完成,当滚轮滚动到下拉框底部时,设置一个离底部的距离像素值,监听这个距离,当距离小于我们设置的距离时,触发监听事件,从数据库获取数据并塞到我们的下拉框中。

由于饿了么组件提供的el-select框没有监测鼠标滚轮的属性,因此我们可以自定义一个vue指令用于监听鼠标滚轮事件。

第一步:定义自定义vue指令

directives: {
    'el-select-loadmore': {
      bind(el, binding) {
        // 获取element-ui定义好的scroll盒子 监听滚动条加载数据
        const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
        const debouncedScroll = debounceWrapper(function () {
          const condition = SELECTWRAP_DOM.scrollHeight - SELECTWRAP_DOM.scrollTop - SELECTWRAP_DOM.clientHeight;
          if (condition <= 1) {
            binding.value()
          }
        })
        SELECTWRAP_DOM.addEventListener('scroll', debouncedScroll);
      }
    }
  }

注意:代码中的debouncedScroll添加了防抖事件,目的是为了防止网络抖动,一次性发送多个请求导致数据列表中有相同的数据。

第二步:定义一个下拉框

<el-select 
    v-model="workUnit" 
    filterable 
    v-el-select-loadmore="handleScroll" 
    remote 
    placeholder="请选择高校" 
    @focus="loadInitialOptions" 
    :remote-method="fetchUniversities"
    :default-first-option="true" 
    @change="handleUniversityChange"
    clearable style="width: 200px">
    <el-option v-for="item in universities" :key="item.id" :label="item.workName"
        :value="item.workName">
    </el-option>
</el-select>

第三步:实现页面逻辑

data() {
    return {
        universities: [],
        totalWork: 0,
        workUnitQueryParams: {
        pageNum: 1,
        pageSize: 10,
        workNameLike: ''
      }
    }
},

methods: {
    /* 下拉框动态加载工作单位 */
    // 下拉框聚焦时获取初始数据
    loadInitialOptions() {
      this.fetchUniversities('');
    },
    // 动态加载时远程获取数据方法
    fetchUniversities(value) {
      this.workUnitQueryParams.workNameLike = value; // 模糊搜索字段赋值
      this.workUnitQueryParams.pageNum = 1; // 查询前将页码置为1
      getWorkUnitByPage(this.workUnitQueryParams).then(response => {
        this.universities = response.data.list;
        this.totalWork = response.data.total; // 记录数据总数,用于滚轮加载数据时做判断
      }).catch(error => {
        console.error('Error fetching universities:', error);
      });
    },
    // 下拉框值变化时触发
    handleUniversityChange(value) {
      console.log('Selected University:', value); // 记录一下下拉框中的值,可以不要
    },
    // 手动触发滚轮加载数据
    handleScroll() {
      // 当列表长度小于数据总数时执行方法
      if (this.universities.length < this.totalWork) {
        this.workUnitQueryParams.pageNum += 1; // 每次页码+1,请求后端数据
        getWorkUnitByPage(this.workUnitQueryParams).then(response => {
          // 将数据拼接在原有数据后
          this.universities = this.universities.concat(response.data.list);
          this.totalWork = response.data.total;
        }).catch(error => {
          console.error('Error fetching universities:', error);
        });
      } else {
        return
      };
    },
    /* 下拉框动态加载工作单位 */
}

总结

这个需求的难点在于饿了么提供的select组件没有监听鼠标滚轮事件的属性,因此我们需要手动构造一个函数去让它能够监听到鼠标滚轮事件。同时,由于下拉框是一个比较小的盒子,高度有限,因此当通过滚轮到底部的高度差去判断时,可能因为差值过小而引发抖动问题(一次性发送多个同样的请求),这样会导致数据列表中数据重复,因此手动加个防抖方法。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值