对ElementPlus的el-select二次封装,添加分页和搜索功能,实现一个自定义的下拉选择框

news2024/11/24 17:20:33

组件展示效果图

Vue3 的 elementPlus项目中,我们经常需要使用下拉选择框 (el-select) 来展示大量数据。然而,默认情况下 el-select 不支持分页和搜索功能。本文将介绍如何通过二次封装 el-select 组件来实现这一需求,并使用自定义的 Hook 来简化开发流程。

1. 创建 useCustomOption.js Hook


首先,我们需要创建一个自定义 Hook,用于处理分页搜索逻辑。

// src/composables/useCustomOption.js
import { ref, reactive } from 'vue';
import { listRegion } from '@/api/manage/region'; // 示例 API 调用

/**
 * 自定义选项搜索钩子
 * 该钩子用于在给定的API列表中搜索特定项,通过提供的查询参数来筛选结果
 *
 * @param {Function} listApi - 一个函数,用于获取列表数据
 * @param {string} queryParamsKey - 用于搜索的项的键名
 * @param {string} itemValue - 用于搜索的项的值
 * @param {Object} queryParams - 其他查询参数,用于过滤结果
 * @returns {Object} - 返回一个对象,包含搜索结果和相关方法
 */
export function useCustomOption(listApi, queryParamsKey, itemValue, queryParams) {
  const selectDataList = ref([]); // 数据列表
  const selectPageInfo = reactive({
    pageNum: 1,
    pageSize: 5,
    total: 0,
  });

  // 查询数据列表
  function getSelectDataList(pageNum, pageSize, searchQuery) {
    selectPageInfo.pageNum = pageNum;
    selectPageInfo.pageSize = pageSize;
    const data = { [itemValue]: searchQuery, ...selectPageInfo };
    listApi(data).then(response => {
      selectPageInfo.total = response.total;
      if (response.rows?.length > 0 && searchQuery !== '') {
        // 设置默认值
        queryParams.value[queryParamsKey] = response.rows[0].id;
      }
      selectDataList.value = response.rows;
    });
  }

  // 处理分页器选中项变化事件
  function handleSelectChange(selectedId, searchQuery) {
    queryParams.value[queryParamsKey] = selectedId;
    getSelectDataList(selectPageInfo.pageNum, selectPageInfo.pageSize, searchQuery);
  }

  return {
    selectDataList,
    selectPageInfo,
    getSelectDataList,
    handleSelectChange,
  };
}

2. 创建 ElCustomOptionForSearch.vue 组件


接下来,我们将创建一个自定义的 el-select 组件,该组件将使用上述 Hook 实现分页搜索功能。

<template>
  <!-- 引入Element UI的Select组件,用于创建一个支持分页的数据选择器 -->
  <el-select v-model="copyValue"
             :disabled="disabled"
             filterable
             clearable
             @clear="selectClear"
             placeholder="请选择"
             @change="updateValue"
             :filter-method="debounceFilterMethod"
             @focus="focusMethod"
             class="elPaginationSelect"
  >
    <!-- 为每个数据项生成一个Option,方便用户选择 -->
    <el-option
        v-for="item in dataList"
        :key="item.value"
        :label="item[labelKey]"
        :value="item[valueKey]"
    ></el-option>
    <template #footer>
      <!-- 自定义选择器的后缀,这里放置了一个分页器 -->
      <div style="float: right; margin-right: 10px; padding-bottom: 10px;">
        <el-pagination
            @current-change="handleCurrentChange"
            :current-page="pageInfo.pageNum"
            :page-size="pageInfo.pageSize"
            layout="prev, pager, next, total"
            :total="pageInfo.total"
        ></el-pagination>
      </div>
    </template>
  </el-select>
</template>

<script setup>
import {ref} from 'vue';

// 定义组件属性
const props = defineProps({
  value: String,
  dataList: Array,
  labelKey: String,
  valueKey: String,
  pageInfo: Object,
  disabled: Boolean,
  elSelectClass: Boolean,
});

// 定义组件事件发射器
const emit = defineEmits(['selectChange', 'selectPageChange']);

// 将父组件传入的value值拷贝一份,用于组件内部逻辑处理
const copyValue = ref(props.value);

// 当用户选择了一个不同的选项时触发,更新父组件的值
const updateValue = (select_key) => {
  props.dataList.forEach(item => {
    if (item[props.valueKey] === select_key) {
      props.dataList = item;

      emit('selectChange', select_key, item[props.labelKey]);
      // 避免选中选项后 ->下拉框 执行搜索的bug
      debounceFilterMethod(item[props.labelKey], false)
    }
  })
};


// todo 实时过滤方法,用户在输入框输入内容时会调用,以更新当前页和搜索关键词
import {throttle} from "lodash"; // 引入 lodash 的 throttle 函数:实现节流
// 根据第二个参数判断是否执行
// is_exec默认为true
const filterMethod = (query, is_exec = true) => {
  // 解决当用户选中下拉选项时,会触发两次请求,一次是搜索,一次是选中,所以需要判断是否执行
  if (!is_exec||query==='') {
    return
  }
  // 区分focusMethod 和 输入框输入时为空字符串调用
  if (query === 'focusMethod'){
    query = ''
  }
  console.log("filterMethod", query)
  copyValue.value = query;
  emit('selectPageChange', 1, props.pageInfo.pageSize, query);
};

// debounceFilterMethod是通过lodash 的 throttle 函数对 filterMethod 进行节流处理后返回的一个新方法
const debounceFilterMethod = throttle(filterMethod, 300, {
  leading: true, // 延长开始后调用
  trailing: false, // 延长结束前调用
})


// 当选择器聚焦时调用,如果数据列表为空,则清空搜索关键词
const focusMethod = () => {
  if (!props.dataList || (props.dataList && props.dataList.length === 0)) {
    debounceFilterMethod('focusMethod');
  }
};

// 当用户清空选择器时调用,重置当前页和搜索关键词
const selectClear = () => {
  emit('selectPageChange', 1, props.pageInfo.pageSize, '');
};

// 分页器的当前页发生改变时调用,更新父组件的当前页码
const handleCurrentChange = (pageNum) => {
  console.log("分页") // todo
  props.pageInfo.pageNum = pageNum
  console.log(copyValue.value);
  // 解决分页器bug :当选中选项 -> 查询 -> 会修改pageSize,当前组件的handleCurrentChange->触发多个渲染事件
  emit('selectPageChange', pageNum, props.pageInfo.pageSize, copyValue.value);
};
</script>

<style scoped lang="scss">
// 为选择器自定义样式,去除默认边框,使其更适合分页数据选择的场景
.elPaginationSelect {
  width: 100%;
  border: none !important;
}

// 自定义输入框样式,去除默认边框,设置宽度以适应内容
.elPaginationSelect .el-input__inner {
  border: none !important;
  width: 100%;
}
</style>

3.使用 ElCustomOptionForSearch.vue 组件

现在,您可以在任何 Vue 组件中使用 ElCustomOptionForSearch 组件来实现带有分页和搜索功能的下拉选择框。

使用组件

      <el-form-item label="搜索区域" prop="regionId">
    <!-- 使用ElCustomOptionForSearch这个自定义组件,通过传入必要参数来实现搜索功能 -->
    <!-- v-model绑定的queryParams.regionId是搜索区域的ID,用于双向绑定搜索框的值 -->
    <!-- :data-list传入一个列表数据源,用于渲染搜索选项 -->
    <!-- :label-key和:value-key分别指定列表数据中的属性,用于显示和作为选项的值 -->
    <!-- :pageInfo传入一个分页信息对象,用于控制搜索选项的分页显示 -->
    <!-- :disabled用于控制搜索功能是否禁用 -->
    <!-- :el-select-class表示是否使用Element UI的样式类 -->
    <!-- @selectChange和@selectPageChange分别监听选项变化和分页变化事件,触发相应的处理函数 -->
        <el-custom-option-for-search
            v-model="queryParams.regionId"
            :data-list="selectDataList"
            :label-key="'regionName'"
            :value-key="'id'"
            :pageInfo="selectPageInfo"
            :disabled="false"
            :el-select-class="true"
            @selectChange="handleSelectChange"
            @selectPageChange="getSelectDataList"
        />
      </el-form-item>

使用hook

/** 查询区域列表操作 */
import ElCustomOptionForSearch from "@/components/ElCustomOptionForSearch"
import {listRegion} from "@/api/manage/region.js";
import {useCustomOptionSearch} from "@/components/ElCustomOptionForSearch/hook/useCustomOption.js";

const {selectDataList,selectPageInfo,getSelectDataList,
handleSelectChange} = useCustomOptionSearch(listRegion, "regionId",'regionName',queryParams)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2209021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一周热门|OpenAI 回击马斯克:为了自己的竞争优势,不断骚扰我们;微软、清华团队提出 Diff Transformer

「一周热门」将从【企业动态】【技术前瞻】【政策法规】【专家观点】四部分&#xff0c;带你快速跟进大模型行业热门动态。 企业动态 OpenAI 回击马斯克&#xff1a;为了自己的竞争优势&#xff0c;他不断骚扰我们 日前&#xff0c;OpenAI 指控马斯克在一场法律诉讼中对其进行…

谷歌浏览器 文件下载提示网络错误

情况描述&#xff1a; 谷歌版本&#xff1a;129.0.6668.90 (正式版本) &#xff08;64 位&#xff09; (cohort: Control)其他浏览器&#xff0c;比如火狐没有问题&#xff0c;但是谷歌会下载失败&#xff0c;故推断为谷歌浏览器导致的问题小文件比如1、2M会成功&#xff0c;大…

基于Transformer的诗句生成

基于Transformer的诗句生成 前言相关介绍Transformer一、基本原理与结构二、关键技术三、应用领域四、优缺点 Transformer应用&#xff1a;诗句生成优缺点 前提条件实验环境基于Transformer的诗句生成准备数据集读取数据集分割数据集设置相关参数创建自己DataSet对象定义网络模…

双十一速购清单!如何才能挑到性价比高的宠物空气净化器

对于很多上班族而言&#xff0c;平时都不敢大手大脚的花钱&#xff0c;甚至很想将一份钱掰成两份来用&#xff0c;所以双十一是很多人都不会错过的购物狂欢节。 当然&#xff0c;我这个996的社畜也一样&#xff0c;而且我还养了一只爱掉毛的猫咪&#xff0c;每天下班回去都看到…

光路科技TSN交换机和电力专用交换机即将亮相第31届中国国际电力设备及技术展览会

在全球能源领域正经历深刻转型之际&#xff0c;可再生能源技术的飞跃进步正为电力行业的未来开辟新径。太阳能、风能等绿色能源&#xff0c;凭借其无可比拟的优势&#xff0c;正稳步取代化石燃料&#xff0c;成为电力行业的主流趋势。多国政府积极响应&#xff0c;出台多项政策…

日均千万订单的交易平台设计稿

业务背景 平台主要售卖电子商品和少量特定的实物商品。 经营模式&#xff0c;主要分为平台商家和自营店&#xff0c;自营店的流量占整个平台业务的50%以上&#xff0c;我负责自营店交易履约相关业务。 以前的架构&#xff0c;平台交易和履约中心是所有流量共享&#xff0c;在…

day01-Qt5入门

day01-Qt5入门 1.下载Qtcreate 官网地址&#xff1a;http://qt-project.org/downloads 2.配置环境变量 将类似于 D:\Qt\Qt5.1.1\5.1.1\mingw48_32\bin 的目录添加到环境变量中 3.创建一个新项目 输入自己的项目名称&#xff0c;后面默认下一部 4.运行第一个项目 在窗口…

计算机网络:数据链路层 —— PPP 点对点协议

文章目录 PPP 帧PPP帧的格式PPP帧的透明传输面向字节的异步链路面向比特的同步链路 PPP帧的差错检测 PPP 的工作状态 点对点协议&#xff08;Point-to-Point Protocol&#xff0c;PPP&#xff09;是目前使用最广泛的点对点数据链路层协议&#xff0c;用于在两个节点之间进行数据…

10.12面试题

代理模式 为什么需要代理模式&#xff1f; 1.中介隔离 客户类不想或者不能直接引用委托对象&#xff0c;需要使用代理类作为中介&#xff0c;需要代理类和委托对象都实现同一接口 2.满足开闭原则 若客户类需要委托对象新增某些功能&#xff0c;就需要代理类在调用委托对象…

【ProtoBuf】基础使用与编译

文章目录 ProtoBuf的使用基本使用指定proto3语法package声明符定义消息(message)定义消息字段字段唯一编号 编译序列化与反序列化序列化与反序列化使用 ProtoBuf的使用 流程如下&#xff1a; 编写 .proto文件&#xff0c;定义结构对象(message)及属性内容使用 protoc 编译器编…

常用类(二)--String类的简单总结

文章目录 1.基本介绍1.1创建对象1.2找到对应下标的字符1.3找到对应字符的下标1.4指定位置开始遍历1.5反向进行遍历1.6大小写之间的转换1.7字符串转换为数组1.8元素的替换1.9字符串的分割1.10字符串的截取 2.StringBuilder和StringBuffer2.1 StringBuilder的引入2.2面试题目 1.基…

拆解学习【无线充,EMMC,锂电池电量计,OTA】(二)

主要学习到了&#xff1a;无线充&#xff0c;EMMC&#xff0c;手表CPU方案&#xff0c;锂电池电量计&#xff0c;OTA。 无线充电功能是产品的核心卖点之一&#xff0c;充电头网通过拆解发现&#xff0c;手表内部使用恒玄BES2500BP智能手表单芯片解决方案&#xff0c;内置四核C…

BetterZip怎么导入文件进行压缩?苹果解压软件怎么用?

BetterZip作为苹果系统常用的压缩文件软件之一&#xff0c;具有使用方便、压缩导出格式多、兼容性强等特点。我们要使用BetterZip进行文件压缩时&#xff0c;首先需要将文件导入到BetterZip才可以。 关于BetterZip的文件导入方式&#xff0c;主要有几种&#xff0c;今天我来给…

垂直AI大模型行业全景分析及发展趋势研究报告

2024-10-12调研咨询机构环洋市场咨询出版的【全球垂直AI大模型行业总体规模、主要厂商及IPO上市调研报告&#xff0c;2024-2030】只要调研全球垂直AI大模型总体规模&#xff0c;主要地区规模&#xff0c;主要企业规模和份额&#xff0c;主要产品分类规模&#xff0c;下游主要应…

每日一题|3158. 求出出现两次数字的 XOR 值|哈希

题目给的范围很小&#xff0c;50以内&#xff0c;所以什么数据结构都可以。 这里采用set来维护访问过的数字&#xff0c;利用哈希来提升时间效率。 class Solution:def duplicateNumbersXOR(self, nums: List[int]) -> int:visited set()l []res 0for i in nums:if i i…

游戏如何应对薅羊毛问题

在大众眼里&#xff0c;“薅羊毛”是指在电商领域&#xff0c;“羊毛党”利用平台、商家的促销规则&#xff0c;低价获取商品和服务的行为。如前不久“小天鹅被一夜薅走7000万”的案例震惊全网。 然而实际上&#xff0c;“薅羊毛”现象不仅存在于电商场景&#xff0c;在游戏中…

【Unity】TextMeshPro 3.0.9无法显示emoji表情问题

需要下载TextMeshPro 3.2.x-pre.xxx版本&#xff0c;重新生成Sprite Asset文件解决 注意&#xff1a;若Package Manager没有搜到pre版本&#xff0c;那么可以去github下载到本地&#xff0c;再解压后&#xff0c;将文件夹移动到工程Packages文件夹下&#xff0c;然后打开Packa…

基于SpringBoot的体育商城购物系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

React复习

文章目录 常用的HooksuseStateuseReduceruseRefuseContextuseMemouseCallbackuseEffect 组件通信Props&#xff08;属性&#xff09;Ref&#xff08;引用&#xff09;Context&#xff08;上下文&#xff09;State&#xff08;状态&#xff09;回调函数Event Bus&#xff08;事件…

Python WebSocket 的原理及其应用

Python WebSocket 的原理及其应用 在现代 Web 开发中&#xff0c;实时通信成为了越来越多应用的重要组成部分。尤其是像聊天应用、实时数据更新、在线游戏等场景&#xff0c;服务器与客户端之间的即时数据传输需求非常迫切。在传统的 HTTP 协议中&#xff0c;通信往往是基于请…