el-select远程搜索滑动分页

558 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第8天,点击查看活动详情

el-select是一种非常常用的form表单组件,比如常用的下拉选择,多选,远程搜索等,其中远程搜索很多时候由于搜索时数据太多,为了减轻服务端压力,会采用滑动分页查找的功能。

el-select远程搜索滑动分页

实现原理

el-select远程搜索滑动分页也就是说,接口根据输入框输入的内容进行查找,将内容按照分页进行返回。默认开始返回第一页数据(比如15条,20条甚至30条数据,可以自行决定)。然后滑动列表,当滑到底部的时候再请求接口,继续返回第二页数据,当滑到底部的时候再请求接口,继续返回第三页数据,依此类推,直至返回全部数据。

具体实现

1. 封装el-select组件

<template v-else-if="['autocomplete', 'autocompleteMultiple'].includes(item.type)">
              <el-select
                v-model="item.model"
                filterable
                remote
                :multiple="item.type === 'autocompleteMultiple'"
                :collapse-tags="item.type === 'autocompleteMultiple'"
                :reserve-keyword="item.reserveKey"
                popper-class="default-autocomplete"
                :class="{ 'autocomplete': true, 'is-danger': item.validateObj ? item.validateObj.errorTip : false }"
                :name="item.elemName"
                :placeholder="item.placeholder"
                :disabled="!!item.disabled"
                :remote-method="item.remoteMethod"
                :loading="item.loading"
                @change="autoCompleteChange(key)"
                @focus="autoCompleteFoucus(item)"
              >
                <el-option
                  v-for="(type) in item.values"
                  :key="type.itemKey"
                  :label="type.itemName"
                  :value="type.itemKey"
                ></el-option>
              </el-select>
            </template>

2. 远程搜索函数

2.1 定义下拉框选项列表fundCodeOpts,请求接口分页参数requsetObj,总数据条数totalRows,输入查询值searchKeyword。

const fundCodeOpts = reactive({
    data: []
  });
  const requsetObj = reactive({
    page: 1
  });
  const totalRows = ref(0); 
  const searchKeyword = ref('');

2.2 核心函数---请求函数

请求函数除了正常请求接口外,还实现了下列功能

  1. 判断是否是滑动到底部继续请求,如果是的话继续往fundCodeOpts后追加数据,否则需将fundCodeOpts重新置空
  2. 拿到数据之后判断当前fundCodeOpts是否是所有数据,如果是,将分页查询参数的页数置为1,去除监听函数,如果是需要找到当前下拉列表的元素(注意一定要是overflow: auto的可以滚动的元素),并为其绑定监听函数。
const editObj = reactive({
    fundCode: {
      name: 'fundCode',
      text: '选择产品',
      type: 'autocomplete',
      model: '',
      value: '',
      clearable: true,
      loading: loading,
      reserveKey: false,
      placeholder: '请输入基金代码或名称',
      values: fundCodeOpts.data,
      validateObj: {
        errorTip: '',
        required: true,
        ifRequiredFill: false
      },
      remoteMethod: (query, addFlag = false) => {
        loading.value = true;
        if (!addFlag) {
          fundCodeOpts.data = [];
        }
        const url = globObj.$api.fundSearch;
        if (query === undefined) return;
        searchKeyword.value = query;
        globObj.$axios.get(url, {
          params: {
            pageNum: requsetObj.page,
            pageSize: 20,
            query: query,
          }
        }).then((res) => {
          let arr = res.data.res.list || [];
          totalRows.value = res.data.res.totalRows;
          loading.value = false;
          arr.forEach((item) => {
            fundCodeOpts.data.push({
              itemKey: item.fundCode,
              itemName: item.fundName
            });
          });
        })
        .catch((err) => {
          loading.value = false;
          console.log(err);
        })
        .finally(() => {
          if (fundCodeOpts.data && fundCodeOpts.data.length < totalRows.value) {
            const parentDom = document.querySelector('.el-select-dropdown.default-autocomplete').querySelectorAll('.el-select-dropdown__wrap.el-scrollbar__wrap.el-scrollbar__wrap--hidden-default');
            parentDom.forEach((e, idx) => {
              if ( e.querySelector('.el-select-dropdown__list') ) {
                dom.value = parentDom[idx];
                dom.value.addEventListener(
                  'scroll',
                  scrollAddEventFn,
                  true
                );
              }
            });
          } else {
            requsetObj.page = 1;
            dom.value?.removeEventListener('scroll', scrollAddEventFn, true);
          }
          editForm.value.changeEditModelVal(
            'fundCode',
            'values',
            fundCodeOpts.data
          );
        });
      }
    },
    holdAmount: {
      name: 'holdAmount',
      text: '持有金额',
      type: 'input',
      model: '',
      value: '',
      unitModel: '1',
      clearable: true,
      moreUnit: true,
      placeholder: '请输入',
      validateObj: {
        errorTip: '',
        required: true,
        ifRequiredFill: false,
        regExp: [
          {
            err: '只能输入整数或小数(保留两位小数)',
            reg: '^(?!(0[0-9]{0,}$))[0-9]{0,}[.]{0,}[0-9]{1,2}$',
          },
        ],
      },
      moreValues: [
        {
          itemKey: '1',
          itemName: '元'
        },
        {
          itemKey: '2',
          itemName: '万元'
        }
      ]
    },
    holdIncome: {
      name: 'holdIncome',
      text: '持有收益',
      type: 'input',
      model: '',
      value: '',
      unitModel: '1',
      clearable: true,
      moreUnit: true,
      placeholder: '请输入',
      validateObj: {
        errorTip: '',
        required: true,
        ifRequiredFill: false,
        regExp: [
          {
            err: '只能输入整数或小数(保留两位小数)',
            reg: '^(?!(0[0-9]{0,}$))[0-9]{0,}[.]{0,}[0-9]{1,2}$',
          },
        ],
      },
      moreValues: [
        {
          itemKey: '1',
          itemName: '元'
        },
        {
          itemKey: '2',
          itemName: '万元'
        }
      ]
    }
  });

2.3 实现滑动监听函数

当滑动到列表底部时,将分页参数的页数+1,然后请求接口。

const scrollAddEventFn = (e) => {
    const self = e.target;
    if (self.scrollHeight - self.scrollTop <= self.clientHeight) {
      requsetObj.page++
      editObj.fundCode.remoteMethod(searchKeyword.value, true);
    }
};

实现效果

滑动下拉框可以加载更多数据

f26a77b82a8088dbecd27cd1a3d746e.jpg