element 提供了 el-select组件,并且支持远程搜索,但是对于数据量大需要翻页的场景并未提供相应配置,所以自己写了一个通用组件,作为记录

初始化控件,定义传入参数

将远程查询的接口封装为函数,作为参数传入组件,可以适应多种场景

<script lang="ts" setup>
import { nextTick, onMounted, ref, watch } from 'vue';
import { message } from "@/utils/message"; interface FetchParams {//远程搜索使用的参数
[key: string]: any;
} const props = defineProps({
fetchData: {//传入进行查询的接口
type: Function,
required: true
},
modelValue: {//select 组件绑定的值
type: [String, Number],
default: ''
},
name: {//下拉框无对应选项的时候用于填充到选项里的值
type: String,
default: ''
},
placeholder: String,
disabled: Boolean,
param: {//查询接口调用的参数
type: Object,
default: () => ({})
}
});

调用传入函数获取远程数据

对传入函数的基本调用以及一些异常处理,loading的值是el-select的配置项,这里需要注意的是在配置了loading = true时,刷新下拉框会内容时会明显看到选项闪烁一下,如果不希望展示搜索刷新的效果,就不要配置loading

const getData = async (params: FetchParams, isLoadMore = false) => {
if (!hasMore.value && isLoadMore) return; loading.value = true;
try {
const res = await props.fetchData(params);
if (!res.error) {
const newItems = res.items?.map(item => ({
label: item.name,
value: item.id
})) || []; if (isLoadMore) {
// 加载更多时,追加数据
itemList.value = [...itemList.value, ...newItems];
} else {
// 首次加载或搜索时,替换数据
itemList.value = newItems;
} // 如果有 name 值,确保它在列表中
if (props.name && value.value) {
const existingItem = itemList.value.find(item => item.value === value.value);
if (!existingItem) {
itemList.value = [{
label: props.name,
value: value.value
}, ...itemList.value];
}
} // 判断是否还有更多数据
hasMore.value = newItems.length === params.MaxResultCount;
totalItems.value = itemList.value.length;
} else {
// 如果接口返回错误,清空数据
itemList.value = [];
hasMore.value = false;
totalItems.value = 0;
}
} catch (error) {
// 如果发生错误,清空数据
itemList.value = [];
hasMore.value = false;
totalItems.value = 0;
message(error, { customClass: 'el', type: 'error' });
} finally {
loading.value = false;
}
};

远程搜索方法

// 远程搜索方法
const remoteSearch = debounce(async (query: string) => {
currentPage.value = 1; // 重置页码
hasMore.value = true; // 重置加载更多状态
if (query) {
const params: FetchParams = {
...props.param,
skipCount: 1,
MaxResultCount: 10,
keyword: query
};
await getData(params);
} else {
// 如果搜索词为空,则加载初始数据
const params: FetchParams = {
...props.param,
skipCount: 1,
MaxResultCount: 10
};
await getData(params);
}
}, 300);

下拉滚动事件监听

这里就是最坑的地方了,因为el-select组件被封装过,所以@scroll.native不会有任何效果。为了实现下拉框的滚动加载功能,只能用@visible-change 来监听下拉框,并在下拉框状态变化的时候添加下拉滚动事件

const handleVisibleChange = async (visible) => {
if (visible) {
// 先清空数据
itemList.value = [];
totalItems.value = 0;
hasMore.value = true;
currentPage.value = 1; // 加载初始数据
const params: FetchParams = {
...props.param,
skipCount: 1,
MaxResultCount: 10
};
await getData(params); // 添加滚动事件监听
const dropdown = document.querySelector('.myselect-loadmore .el-select-dropdown__wrap');
if (dropdown) {
dropdown.addEventListener('scroll', handleScroll);
// 重置滚动位置
dropdown.scrollTop = 0;
}
} else {
// 移除滚动事件监听
const dropdown = document.querySelector('.el-select-dropdown');
if (dropdown) {
dropdown.removeEventListener('scroll', handleScroll);
}
}
}; //防抖函数
function debounce<T extends (...args: any[]) => any>(func: T, delay: number) {
let timeout: NodeJS.Timeout;
return function (this: any, ...args: Parameters<T>) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), delay);
};
} const handleScroll = debounce(async (event) => {
// 判断是否滚动到底部
const bottom = event.target.scrollHeight === event.target.scrollTop + event.target.clientHeight;
if (bottom && !loading.value && hasMore.value) {
currentPage.value++;
// 调用父组件传递的函数,并传入子组件的参数
const params: FetchParams = {
...props.param,
skipCount: currentPage.value,
MaxResultCount: 10
};
await getData(params, true);
}
}, 100);

el-select 组件配置

popper-class的设置是为了让事件能够准确绑定到下拉框,不添加该属性可能导致事件被绑定到父组件上面

<template>
<el-select
v-model="value"
class="myselect"
:placeholder="placeholder || '请选择!'"
popper-class="myselect-loadmore"
filterable
remote
remote-show-suffix
:remote-method="remoteSearch"
clearable
:disabled="disabled"
@visible-change="handleVisibleChange"
@update:modelValue="(val) => emit('update:modelValue', val)">
<el-option v-for="(item, index) in itemList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>

父组件调用示例

              <SelectCommon v-model="Id" :fetch-data="getList" :param="selectParams"
placeholder="请选择" />

适用于Vue3+ts+element的场景,组件完整代码已经上传至github,文件添加到项目可以直接调用。

地址:https://github.com/LearnerPing/SelectCommon.git

如果你觉得还算好用,请在github上面给我点个star

Vue3+Ts笔记:基于element-UI 实现下拉框滚动翻页查询通用组件的更多相关文章

  1. Vue+Element UI一个下拉框传字典值和对应字典Label

    <el-select @change="getDeptName" v-model="form.deptCode"> <el-option v- ...

  2. vue开发 element的select下拉框设定初值后,不能重新选择的问题

    问题描述: 用的element的select可多选的下拉选框,在回显后有初始值的情况下,不能修改,也不能再选择 如图,明明点击了一般内勤主管,但没有任何反应 <el-select v-model ...

  3. js基于json的级联下拉框

    级联下拉列表是项目中常用到的.比如省市县,比如企业性质等,做成一个js通用组件, 在静态页出来后可以直接插入,将数据和html静态页做一个解耦. 贴出来抛砖引玉吧. /** * @author sun ...

  4. 基于bootstrap-multiselect.js的下拉框联动

    背景:当option特别多时,一般的下拉框选择起来就有点力不从心了,所以使用multiselect是个很好的选择,可以通过输入文字来选择选项很方便,但是有一个需要下拉框联动,网上找了半天才找到解决方法 ...

  5. 【WPF学习笔记】之如何设置下拉框读取SqlServer数据库的值:动画系列之(一)

    先前条件:设置好数据库,需要三个文件CommandInfo.cs.DbHelperSQL.cs.myHelper.cs,需要修改命名空间,参照之前随笔http://www.cnblogs.com/Ow ...

  6. 关于Vue+iview的简单下拉框滚动加载

    话不多说,直接上代码,作用是下拉框内容无限滚动加载: Html: <FormItem style="position:relative" label="用户名:&q ...

  7. Bootstrap 学习笔记2 栅格系统 辅助类下拉框

    辅助类和响应式工具: 颜色和字体相同 响应式工具: 图标菜单按钮组件: btn-group 按钮式下拉菜单

  8. javaFX笔记----ComboBox模仿qq账号下拉框删除账号

    myComboBox.setCellFactory( new Callback<ListView<String>, ListCell<String>>() { @O ...

  9. bootstrap下拉框式标签页

    <ul id="myTab" class="nav nav-tabs"> <li class="active"> & ...

  10. 基于Bootstrap的下拉框插件bootstrap-select

    写在前面: 在这次的项目中,没有再使用liger-ui做为前端框架了,改为了Bootstrap,这次也好接触下新的技术,在学习的过程中发现,Bootstrap的一些组件基本都是采用class的形式,就 ...

随机推荐

  1. 【Abaqus】Composite Layup建模

    abaqus 的3个复合材料建模途径: 传统的material->section->orientation->step->job的建模方式 Composite Layup建模方 ...

  2. xss学习及xss-lab解题记录

    什么是XSS(跨站脚本攻击) SQL注入是服务端将用户输入的数据当成SQL代码去执行 XSS可以理解为服务端把用户输入的数据当成前端代码去执行 前端代码->主要是js代码 两个关键条件: 第一个 ...

  3. Android 实现人脸识别 活体检测以及人脸搜索

    关于「保护伞FaceAI SDK」 Umbrella FaceAI SDK is on_device Offline Android Face Detection .Recognition .Live ...

  4. 导出和导入word样式模板

    对于自己配置过之后常用的word样式可以导出作为样式模板, 可以重复使用. 举例说一下哪些是常用的word样式, 例如: (常见的): 中文的内容的样式, 中英文分别设置不同的样式 (比较高级的)多级 ...

  5. 【vscode】vscode配置python

    [vscode]vscode配置python 前言 ‍ 每次配环境的经历,其实都值得写一篇博客记录一下,以便于自己以后查阅. ‍ 笔者环境: win10 ‍ 过程 ‍ step1:python解释器下 ...

  6. zstd压缩算法概述与基本使用

    本文仅关注zstd的使用,并不关心其算法的具体实现 并没有尝试使用zstd的所有功能模式,但是会简单介绍每种模式的应用场景,用到的时候去查api吧 step 0:why zstd? zstd是face ...

  7. go 组合函数 Collection

    我们经常需要程序在数据集上执行操作,比如选择满足给定条件的所有项,或者将所有的项通过一个自定义函数映射到一个新的集合上. 在某些语言中,会习惯使用泛型. Go 不支持泛型,在 Go 中,当你的程序或者 ...

  8. Qt安装好后如何添加或删除组件

    一.使用MaintenanceTool进行管理 1.在Qt的安装路径下找到MaintenanceTool.exe,双击打开后,界面如下,(本人用的是5.10版本) 2.直接选择Skip,进入如下界面, ...

  9. 分布式一致性算法-Paxos、Raft、ZAB、Gossip

      为什么需要一致性 数据不能存在单个节点(主机)上,否则可能出现单点故障. 多个节点(主机)需要保证具有相同的数据. 一致性算法就是为了解决上面两个问题. 一致性算法的定义 一致性就是数据保持一致, ...

  10. 元模型对AI的哲学意义:让机器真正"懂"世界

    元模型对AI的哲学意义:让机器真正"懂"世界 (用日常语言和比喻解释) 1. 传统AI像"死记硬背的学生" 问题:现在的ChatGPT就像背了无数词典的人,能对 ...