React+Antd实现省、市区级联下拉多选组件(支持只选省不选市)

news2024/11/13 16:14:07

 1、效果

是你要的效果,咱们继续往下看,搜索面板实现省市区下拉,原本有antd的Cascader组件,但是级联组件必须选到子节点,不能只选省,满足不了页面的需求

2、环境准备

1、react18

2、antd 4+

3、功能实现

原理:封装一个受控组件,该组件就是两select基本组件

1、首先,导入需要的组件:

import { Select, Space, Tag } from 'antd';

 2、定义2个状态变量来存储选中省和市的下拉枚举

  const [firstOptions, setFirstOptions] = useState<any>([]);
  const [secondOptions, setSecondOptions] = useState<any>([]);

 3、组件可接收的props子属性 如下:

  •  options: 省市级联数据
  •  value: 已选中的值
  •  width:slect框的宽度
  •  firstPlaceholder 第一个select框的placeholder
  • secondPlaceholder第二个select框的placeholder
  •  onChange: 选中的值发生变化时回调

 4、创建handleFirstChange函数来处理第一个select框的change事件,更新第二个select框的下拉项和值

  // 第一个select生变化
  const handleFirstChange = (data: any) => {
    if (!isEmpty(data) && data.value) {
      let insertIndex = (options || []).findIndex((item: any) => {
        return item?.value === data?.value;
      });
      setSecondOptions(options?.[insertIndex]?.children || []);
      onChange({ first: [data] });
    } else {
      setSecondOptions([]);
      onChange(null);
    }
  };

 5、创建onSecondChange 函数来处理第二个select框的change事件,将选中的值回传给父组件

  // 第二个select发生变化
  const onSecondChange = (data: any) => {
    if (!isEmpty(value) && value.first) {
      if (!isEmpty(data)) {
        onChange({
          ...value,
          second: mode === 'multiple' ? (data || []).filter((item: any) => !isNil(item?.label)) : [data],
        });
      } else {
        onChange({ first: value.first, second: null });
      }
    } else {
      onChange(null);
    }
  };

 6、最后,使用2个select组件渲染,并将选中状态和change事件绑定到对应的属性上:

return (
    <>
      <Space wrap={false} direction="horizontal" size={12}>
        <Select
          defaultValue={firstOptions[0]}
          style={{ width: width }}
          onChange={handleFirstChange}
          placeholder={firstPlaceholder || '请选择'}
          value={value?.first}
          options={firstOptions}
          labelInValue
          allowClear
        />
        <Select
          style={{ width: width }}
          value={value?.second || []}
          onChange={onSecondChange}
          placeholder={secondPlaceholder || '请选择'}
          options={secondOptions}
          {...mode === "multiple" ? { mode: "multiple", maxTagCount: 'responsive', tagRender: tagRender } : {}}
          labelInValue
          allowClear
        />
      </Space>
    </>
)

 7、完整代码如下:

import { Select, Space, Tag } from 'antd';
import clsx from 'clsx';
import { isEmpty, isNil } from 'lodash';
import { useEffect, useState } from 'react';
import './index.less';

const MultipleCascaderSelect = (props: any) => {
  const {
    options,
    value,
    onChange,
    width = 160,
    firstPlaceholder,
    secondPlaceholder,
    mode = 'multiple'
  } = props;

  const [firstOptions, setFirstOptions] = useState<any>([]);
  const [secondOptions, setSecondOptions] = useState<any>();

  useEffect(() => {
    setFirstOptions(options || []);
    if (Array.isArray(value?.first) && value.first.length) {
      let findIndex = (options || []).findIndex((item: any) => {
        return item.value === value.first?.[0].value;
      });
      setSecondOptions(options[findIndex]?.children || []);
    } else {
      setSecondOptions([]);
    }
  }, [options, value]);

  // 第一个select生变化
  const handleFirstChange = (data: any) => {
    if (!isEmpty(data) && data.value) {
      let insertIndex = (options || []).findIndex((item: any) => {
        return item?.value === data?.value;
      });
      setSecondOptions(options?.[insertIndex]?.children || []);
      onChange({ first: [data] });
    } else {
      setSecondOptions([]);
      onChange(null);
    }
  };

  // 第二个select发生变化
  const onSecondChange = (data: any) => {
    if (!isEmpty(value) && value.first) {
      if (!isEmpty(data)) {
        onChange({
          ...value,
          second: mode === 'multiple' ? (data || []).filter((item: any) => !isNil(item?.label)) : [data],
        });
      } else {
        onChange({ first: value.first, second: null });
      }
    } else {
      onChange(null);
    }
  };
  const tagRender = ({ label, closable, onClose }: any) => {
    const isLongTag = `${label}`.length > 4;
    return (
      <Tag
        color={label.props?.color}
        closable={closable}
        onClose={onClose}
        className={clsx([
          'text-sky-400 bg-sky-400/10 text-sm font-normal leading-5',
          // 'border border-solid border-sky-400/50',
          'max-w-[110px] border-none',
          // 'whitespace-nowrap text-ellipsis overflow-hidden'
        ])}
      >
        <span>{isLongTag ? `${label.slice(0, 4)}...` : label}</span>
        {/* {isLongTag ? (
          <Tooltip
            title={label}
            key={label}
            rootClassName={clsx('toolTipCard')}
            placement="top"
          >
            <span>{label.slice(0, 4)}...</span>
          </Tooltip>
        ) : (
          <span>{label}</span>
        )} */}
      </Tag>
    );
  };
  return (
    <>
      <Space wrap={false} direction="horizontal" size={12}>
        <Select
          defaultValue={firstOptions[0]}
          style={{ width: width }}
          onChange={handleFirstChange}
          placeholder={firstPlaceholder || '请选择'}
          value={value?.first}
          options={firstOptions}
          labelInValue
          allowClear
        />
        <Select
          style={{ width: width }}
          value={value?.second || []}
          onChange={onSecondChange}
          placeholder={secondPlaceholder || '请选择'}
          options={secondOptions}
          {...mode === "multiple" ? { mode: "multiple", maxTagCount: 'responsive', tagRender: tagRender } : {}}
          labelInValue
          allowClear
        />
      </Space>
    </>
  );
};

export default MultipleCascaderSelect;

组件调用

 <MultipleCascaderSelect
     width={162}
     options={enumData|| []}
     firstPlaceholder="请选择"
     secondPlaceholder="请选择"
 />

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

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

相关文章

ThreadLocal及阿里(TransmittableThreadLocal,TTL)分析

TTL类关系图 ThreadLocal <- InheritableThreadLocal <- TransmittableThreadLocal 1. ThreadLocal ThreadLocal 类提供线程本地&#xff08;局部&#xff09;变量。每个线程都有自己独立初始化的变量副本。 TheadLocal 允许我们存储仅由特定线程访问的数据&#xff0c;…

JavaWeb后端开发(第一期):Maven基础、Maven的安装配置、如何创建maven项目模块、maven的生命周期

Java后端开发&#xff1a;2024年2月6日 -> LiuJinTao 文章目录 JavaWeb后端开发&#xff08;第一期&#xff09; &#xff1a; maven基础一、 maven介绍1.1 什么maven呢&#xff1a;1.2 maven的作用1.3 maven 模型1.4 maven 仓库 二、maven 安装2.1 配置本地仓库2.2 配置阿里…

c#cad 创建-多线段(三)

运行环境 vs2022 c# cad2016 调试成功 一、程序说明 AutoCAD中创建多段线的。具体解释如下&#xff1a; 获取当前文档和数据库&#xff0c;并创建一个编辑器&#xff08;用于与用户交互&#xff09;。使用事务处理的方式&#xff0c;开始对数据库的操作。打开模型空间&…

LeetCode-第171题-Excel表的序列号

1.题目描述 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 2.样例描述 3.思路描述 遍历时将每个字母与 A 做减法&…

【开源】SpringBoot框架开发厦门旅游电子商务预订系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 景点类型模块2.2 景点档案模块2.3 酒店管理模块2.4 美食管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 学生表3.2.2 学生表3.2.3 学生表3.2.4 学生表 四、系统展示五、核心代码5.1 新增景点类型5.2 查询推荐的…

Linux——进程间通信:管道

我们在开发过程中&#xff0c;可能会碰到两个或多个进程需要协同进行&#xff0c;这两个进 程之间有着一定的关系&#xff0c;这个进程可能会需要另一个进程的某些消息来达 到自己的目的&#xff0c;或者是一个进程控制着另一个进程&#xff0c;又或者是需要某种资 源的共享。但…

速度规划:s形曲线应用(变速 停车)opencv c++显示(3)

理论篇 先看该篇&#xff0c;这里沿用了里面的变量。 应用推导篇 分为变速和停车两部分&#xff08;字迹潦草&#xff0c;可结合代码看&#xff09; 代码篇 变速函数入口&#xff1a; velocityPlanner vp; vp.SetParameters(0, 1);停车函数入口&#xff1a; ParkingVelo…

挑战杯 python+大数据校园卡数据分析

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于yolov5的深度学习车牌识别系统实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;3分 该项目较为新颖&am…

23.HarmonyOS App(JAVA)堆叠布局StackLayout使用方法

不常用 StackLayout直接在屏幕上开辟出一块空白的区域&#xff0c;添加到这个布局中的视图都是以层叠的方式显示&#xff0c;而它会把这些视图默认放到这块区域的左上角&#xff0c;第一个添加到布局中的视图显示在最底层&#xff0c;最后一个被放在最顶层。上一层的视图会覆盖…

mysql入门到精通005-基础篇-约束

1、概述 1.1 概念 约束是作用于表中字段上的规则&#xff0c;用于限制储存在表中的数据。 1.2 目的 保证数据库中数据的正确性、有效性和完整性。 1.3 常见的约束分类 一旦谈到外键&#xff0c;则至少涉及2张表约束是作用于表中字段上的&#xff0c;可以在创建表/修改表的…

机器学习-梯度下降法

不是一个机器学习算法是一种基于搜索的最优化方法作用&#xff1a;最小化一个损失函数梯度上升法&#xff1a;最大化一个效用函数 并不是所有函数都有唯一的极值点 解决方法&#xff1a; 多次运行&#xff0c;随机化初始点梯度下降法的初始点也是一个超参数 代码演示 impor…

【语音合成】中文-多情感领域-16k-多发音人

模型介绍 语音合成-中文-多情感领域-16k-多发音人 框架描述 拼接法和参数法是两种Text-To-Speech(TTS)技术路线。近年来参数TTS系统获得了广泛的应用&#xff0c;故此处仅涉及参数法。 参数TTS系统可分为两大模块&#xff1a;前端和后端。 前端包含文本正则、分词、多音字预…

在angular12中proxy.conf.json中配置详解

一、proxy.conf.json文件的目录 二、proxy.conf.json文件中的配置 "/xxx/api": {"target": "地址/api","secure": false,"logLevel": "debug","changeOrigin": true,"pathRewrite": {"…

【华为 ICT HCIA eNSP 习题汇总】——题目集13

1、以下在项目规划阶段中需要完成的工作是&#xff08;&#xff09;。 A、确定技术方案 B、了解项目背景 C、选择网络产品 D、规划 IP 地址 考点&#xff1a;网络规划与设计 解析&#xff1a;&#xff08;B&#xff09; 确定技术方案是在网络规划的设计阶段完成的工作&#xff…

团队管理-如何组织好一场会议

一、不同维度分析 1、按照时间维度 可分为 会前、会中、会后 会前 1、确定会议时间 尽可能选择参与者都空闲的时间&#xff0c;确保参与者都有时间可以参加&#xff0c;可以提前询问大家有空的时间&#xff0c;如果部分人没有时间但是会议比较紧急&#xff0c;可以让其选择…

2024:AI 大冒险

2024&#xff1a;AI 大冒险 2023 年就像一场疯狂的过山车&#xff0c;现在让我们一起系好安全带&#xff0c;来预测一下 2024 年的五大惊心动魄事件吧&#xff01; 一、AI 惹祸升级 嘿&#xff0c;2024 年可要小心了&#xff01;AI 这家伙可能会变得更调皮捣蛋。人们可能会用…

Bootstrap5 导航组件和面包屑

Bootstrap5 导航组件和面包屑 Bootstrap5 提供了一种简单快捷的方法来创建基本导航&#xff0c;它提供了非常灵活和优雅的选项卡和Pills等组件。 Bootstrap5 的所有导航组件&#xff0c;包括选项卡和Pills&#xff0c;都通过基本的 .nav 类共享相同的基本标记和样式。 使用 B…

springboot162基于SpringBoot的体育馆管理系统的设计与实现

体育馆管理系统 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本体育馆管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕…

搜索引擎DuckDuckGo代理指南

DuckDuckGo作為一款搜索引擎&#xff0c;同時擁有自己的流覽器&#xff0c;高度保護用戶隱私&#xff0c;使其有別於其他收集和利用用戶數據進行定向廣告的搜索引擎。然而&#xff0c;單獨使用DuckDuckGo並不能保證線上完全匿名。如果你想進一步保護隱私&#xff0c;那就需要使…

深度解析源码,Spring 如何使用三级缓存解决循环依赖

目录 一. 前言 二. 基础知识 2.1. 什么是循环依赖&#xff1f; 2.2. 三级缓存 2.3. 原理执行流程 三. 源码解读 3.1. 代码入口 3.2. 第一层 3.3. 第二层 3.4. 第三层 3.5. 返回第二层 3.6. 返回第一层 四. 原理深度解读 4.1. 什么要有三级缓存&#xff1f; 4.2.…