select组件 消费 模糊搜索/分页接口 编码实践

需求场景

有些后端接口是分页并支持模糊搜索的,我们需要编写代码用select组件去展示列表数据,并且支持搜索能力(用select组件消费这个接口)

源码

html:

html 复制代码
<某某组件库-select
  v-model="formParams.model.sceneModelList"
  placeholder="请选择界面"
  :filterable="true"
  :remote="true"
  :debounce="500"
  multiple
  :remote-method="getSceneModelListByKeyword"
  :loading="isGettingSceneModelList"
  value-key="id"
  :formatter="formatterDataModel"
  @blur="onBlur"
  @scroll-bottom="selectScrollBottom"
>
  <某某组件库-option
    v-for="item in sceneModelList"
    :key="item.id"
    :label="item.name"
    :value="item"
  />
  <某某组件库-loading v-if="isScrollLoading" size="small" />
</某某组件库-select>

js:

typescript 复制代码
// 数据模型select分页相关
// 数据模型select滚动触底时触发分页接口访问
const isGettingSceneModelList = ref(true);
const sceneModelList = ref<TDataModelList>([]);
const isScrollLoading = ref(false);
const noMoreData = ref(false);
let page = 1;
const size = 20;
let keyword = '';
// 滚动触底回调
const selectScrollBottom = async () => {
  if (noMoreData.value) return;
  isScrollLoading.value = true;
  page += 1;
  const params = {
    page,
    size,
    keyword,
  };
  const [error, res] = await to(getSceneModelList(params));
  if (error) {
    return Message({ message: error.message, type: 'error' });
  }
  if (res.data.items === null || res.data.items.length === 0) {
    isScrollLoading.value = false;
    noMoreData.value = true;
    return;
  }
  sceneModelList.value = [...sceneModelList.value, ...(res.data.items || [])];
  isScrollLoading.value = false;
};
// 远程搜索回调
const getSceneModelListByKeyword = async (input = '') => {
  page = 1;
  keyword = input;
  isGettingSceneModelList.value = true;
  const params = {
    page,
    size,
    keyword,
  };
  const [error, res] = await to(getSceneModelList(params));
  if (error) {
    return Message({ message: error.message, type: 'error' });
  }
  sceneModelList.value = res.data.items || [];
  isGettingSceneModelList.value = false;
};
getSceneModelListByKeyword();
// 失去焦点时清空搜索关键词
const onBlur = () => {
  keyword = '';
};
// 数据模型格式化
const formatterDataModel = ({ value }: { value: IDataModelItem }) => {
  return value?.name;
};

实现select适配分页

比如我们假定一页的size为20,我们的目标就是最初select请求第一页(page = 1)的20条数据,后面每次滚动触底时再请求第二页、第三页...的数据,直至后端数据全部被请求完毕,也就是page过大导致返回数据为空时,我们不再触发请求的逻辑。

我们暂时不考虑搜索能力的实现,所以暂时把搜索参数keyword置空,编写如下代码:

typescript 复制代码
// 数据模型select滚动触底时触发分页接口访问
const isGettingSceneModelList = ref(true); // 整个select的loading控制变量
const sceneModelList = ref<TDataModelList>([]); // 存放下拉列表
const isScrollLoading = ref(false); // loading控制变量(在select-option最下面放了一个loading)
const noMoreData = ref(false); // 标识后端是否已经没有数据了
let page = 1;
const size = 20;
let keyword = '';
​
// 滚动触底回调, 对应select的scroll-bottom事件
const selectScrollBottom = async () => {
  if (noMoreData.value) return; // 如果noMoreData为true, 则没必要触发函数体执行return即可
  isScrollLoading.value = true; // 展示最下面的loading
  page += 1; // 请求下一页的数据(追加至List列表)
  const params = {
    page,
    size,
    keyword,
  };
  const [error, res] = await to(getSceneModelList(params));
  if (error) {
    return Message({ message: error.message, type: 'error' });
  }
  // 如果后端无数据返回, noMoreData置为true
  if (res.data.items === null || res.data.items.length === 0) {
    isScrollLoading.value = false; // 下拉列表最下面的loading结束
    noMoreData.value = true;
    return;
  }
  // 追加后端返回的数据至list
  sceneModelList.value = [...sceneModelList.value, ...(res.data.items || [])];
  isScrollLoading.value = false; // 下拉列表最下面的loading结束
};

实现select支持远程搜索

说白了我们需要维护用户的输入,即keyword变量,当搜索时更新keyword这个请求参数,失去焦点时清空即可。

搭配select组件的filterable = "true"即开启输入搜索, remote = "true" (默认为false,即针对列表内的数据进行搜索)即调用remote-method 指定的方法进行搜索(或者说用户输入时具体执行的逻辑全由remote-method决定了),remote-method = "getSceneModelListByKeyword"即用户输入时执行的回调函数。

编写getSceneModelListByKeyword函数如下:

typescript 复制代码
// 远程搜索回调
const getSceneModelListByKeyword = async (input = '') => {
  page = 1;
  keyword = input; // 更新外层的keyword, 因为此时的分页请求也是基于当前用户输入的keyword进行搜索的
  isGettingSceneModelList.value = true; // 搜索时整个select置为loading态
  const params = {
    page,
    size,
    keyword,
  };
  const [error, res] = await to(getSceneModelList(params));
  if (error) {
    return Message({ message: error.message, type: 'error' });
  }
  // 更新list为搜索到的数据
  sceneModelList.value = res.data.items || [];
  isGettingSceneModelList.value = false;
};
// 组件挂载之前调用一次getSceneModelListByKeyword, 获取初始数据, 其实也可以借助触底方法来获取初始数据, 但是触底方法控制的loading是下拉列表最底部的, 而非整个select的loading, 所以调用远程搜索方法获取初始数据最为合适
getSceneModelListByKeyword();
// 失去焦点时清空搜索关键词keyword
const onBlur = () => {
  keyword = '';
};
相关推荐
郑州光合科技余经理3 小时前
本地生活服务系统:成品模块和定制接口怎么划界
java·前端·人工智能·后端·系统架构·php·ai编程
平头哥~6 小时前
Day 07 _ 那条 1px 的线,为什么在手机上忽粗忽细
前端·css·样式·学习资料
小江的记录本7 小时前
【CSS】CSS 动画:transition、animation、transform、CSS3 新特性(附《思维导图》)
前端·css·安全·spring·前端框架·css3·动画
circuitsosk7 小时前
任务规划器的三种范式对比:ReAct、Plan-and-Execute 与 Tree-of-Thought 在真实业务中的取舍
前端·javascript·python·react.js·llm·ai agent
hzxpaipai8 小时前
企业官网技术架构拆解:前端、后台、数据库、服务器如何协同
前端·数据库·架构
深念Y10 小时前
Lenovo XiaoXinAir 14 — 性能模式切换
前端·网络
计算机魔术师10 小时前
Meta突然杀进第一梯队:一个新模型,把AI推理成本打下来8倍
前端
IT_陈寒11 小时前
Redis缓存雪崩把我坑惨了,这次长记性了
前端·人工智能·后端
风骏时光牛马11 小时前
提示词工程:大模型效能挖掘与指令设计实战
前端