仿Antd-mobile的Cascader实现省市区联动

为啥不直接用Cascader 级联选择组件呢?主要是因为作为老项目,已经引入了antd-mobile@2.3.4,同时引入v5版本会有兼容性问题。

原始数据格式:

首先需要将后端返回的数据转为前端定义的格式,方便使用:

[{"label": "安徽省","value": "340000","children": [{"label": "安庆市","value": "340800","children": [{"label": "大观区","value": "340803","children": []},...其他区]},...其他市]},...其他省份
]

树结构转数组结构:

研究了下antd-mobile的cascader-view源码,我发现精髓在于将树结构转换成了方便开发的数组:

  //选择的value 一维数组const [value, setValue] = useState([]);const levels = useMemo(() => {const ret = [];//当前列表let currentOptions = options;//是否到底let reachedEnd = false;for (const v of value) {const target = currentOptions.find(option => option['value'] === v);ret.push({selected: target,options: currentOptions,});if (!target || !target['children'] || isEmpty(target['children'])) {reachedEnd = true;break;}currentOptions = target['children'];}if (!reachedEnd) {ret.push({selected: undefined,options: currentOptions,});}return ret;}, [value]);

当未选择时levels结构:

[{//未选中selected: undefined,options: [{"label": "安徽省","value": "340000","children": [{"label": "安庆市","value": "340800","children": [{"label": "大观区","value": "340803","children": []},...其他区]},...其他市]},...其他省份]}
]

选中省份时levels结构:

[{//选中省份"selected": {"label": "安徽省","value": "340000","children": [{"label": "安庆市","value": "340800","children": [{"label": "大观区","value": "340803","children": []},...其他区]},...其他市]},  "options": [{"label": "安徽省","value": "340000","children": [{"label": "安庆市","value": "340800","children": [{"label": "大观区","value": "340803","children": []},...其他区]},...其他市]},...其他省份]},{//未选中"selected": undefined,"options": [{"label": "安庆市","value": "340800","children": [{"label": "大观区","value": "340803","children": []},...其他区]},...其他市]}
]

数据结构清楚以后,编码就相对简单了:

import PopShow from '@/components/PopShow';
import React, { useMemo, useState } from 'react';
//v2版本的
import { Tabs } from 'antd-mobile';
import styles from './index.less';
import { isEmpty } from 'lodash';
import { CheckOutline } from 'antd-mobile-icons';
import classNames from 'classnames';const AddressModal = ({options}) => {const [value, setValue] = useState([]);const [page, setPage] = useState(0);//精髓在于这段代码,将树形结构转为数组const levels = useMemo(() => {const ret = [];//当前列表let currentOptions = options;//是否到底let reachedEnd = false;for (const v of value) {const target = currentOptions.find(option => option['value'] === v);ret.push({selected: target,options: currentOptions,});if (!target || !target['children'] || isEmpty(target['children'])) {reachedEnd = true;break;}currentOptions = target['children'];}if (!reachedEnd) {ret.push({selected: undefined,options: currentOptions,});}return ret;}, [value]);const tabs = useMemo(() => {const ret = levels?.map(level => {if (level?.selected) {return {title: level?.selected['label'],};}return {title: '请选择',};}) || [{title: '请选择',}];//滑动到下一tabsetPage(ret?.length - 1);return ret;}, [levels]);const onItemSelect = (selectValue, depth) => {const next = value.slice(0, depth);if (selectValue !== undefined) {next[depth] = selectValue;}setValue(next);};return <PopShow visible={true}><div className={styles.popShow}><div className={styles.topButtons}><span>取消</span><span>确定</span></div><Tabs tabs={tabs} swipeable={false} page={page}onChange={(_, index) => setPage(index)}tabBarActiveTextColor={'#BB6532'}tabBarInactiveTextColor={'#000000'}tabBarUnderlineStyle={{ display: 'none' }}tabBarTextStyle={{ fontSize: '14px' }}>{levels?.map((level, index) => {const options = level?.options;return (<div className={styles.checklist}>{options?.map(option => {const active = value[index] === option['value'];return <div onClick={() => onItemSelect(option['value'], index)}className={classNames({[styles.active]: active})}><span>{option['label']}</span>{active && <CheckOutline />}</div>;})}</div>);})}</Tabs></div></PopShow>;
};export default AddressModal;
@import (reference) '../../styles/index.less';.popShow {height: 60vh;display: flex;flex-direction: column;overflow: hidden;.topButtons {display: flex;justify-content: space-between;padding: 8*@rem 16*@rem 4*@rem;color: #343434;}.checklist {flex: 1;overflow-y: scroll;&::-webkit-scrollbar {display: none;}& > div {text-align: left;padding: 8*@rem 16*@rem;display: flex;justify-content: space-between;align-items: center;}.active{color: #BB6532;}}:global {.am-tabs-default-bar-tab {width: auto !important;padding-left: 16*@rem;padding-right: 16*@rem;max-width: 33.3%;.textEllipsis;}.am-tabs-default-bar-content {position: relative;&:after {content: '';position: absolute;background-color: #ddd;display: block;z-index: 1;top: auto;right: auto;bottom: 0;left: 0;width: 100%;height: 1px;}}}
}

附上效果图:
QQ录屏20240704104232.gif

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

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

相关文章

jsqlparse工具拦截sql处理和拓展

前置知识 访问者模式 &#xff08;Visitor Pattern&#xff09;是一种行为设计模式&#xff0c;它允许你定义在不改变被访问元素的类的前提下&#xff0c;扩展其功能。通过将操作&#xff08;操作或算法&#xff09;从对象结构中提取出来&#xff0c;可以在不修改这些对象的前…

机器学习与模式识别_清华大学出版社

contents 前言第1章 绪论1.1 引言1.2 基本术语1.3 假设空间1.4 归纳偏好1.5 发展历程1.6 应用现状 第2章 模型评估与选择2.1 经验误差与过拟合2.2 评估方法2.3 性能度量2.3.1 回归任务2.3.2 分类任务 2.4 比较检验2.5 偏差与方差2.5.1 偏差-方差分解2.5.2 偏差-方差窘境 第3章 …

航空数据管控系统-②项目分析与设计:任务2:使用Git或SVN管理项目(可选任务,只介绍Git安装)

任务描述 1、安装Git 2、注册GitHub 3、配置本地库 4、配置远程库 5、使用Git管理项目 任务指导 分为以下几个部分完成&#xff1a; 学会Git的安装&#xff0c;帐号注册本地存储库的管理自己创建一个项目&#xff0c;项目名称为自己的名字&#xff0c;上传到代码仓库&#xff…

符号速率、调制方式、码率、传输速率

符号速率、调制方式、码率&#xff08;比特率&#xff09;和传输速率在通信系统中是相互关联且重要的概念&#xff0c;它们之间的关系可以归纳如下&#xff1a; 一、定义 符号速率&#xff08;Symbol Rate&#xff09;&#xff1a; 也称波特率&#xff08;Baud Rate&#xff…

一文搞懂到底什么是 AQS

日常开发中&#xff0c;我们经常使用锁或者其他同步器来控制并发&#xff0c;那么它们的基础框架是什么呢&#xff1f;如何实现的同步功能呢&#xff1f;本文将详细讲解构建锁和同步器的基础框架--AQS&#xff0c;并根据源码分析其原理。 一、什么是 AQS&#xff1f; (一) AQS…

Element中的日期时间选择器DateTimePicker和级联选择器Cascader

简述&#xff1a;在Element UI框架中&#xff0c;Cascader&#xff08;级联选择器&#xff09;和DateTimePicker&#xff08;日期时间选择器&#xff09;是两个非常实用且常用的组件&#xff0c;它们分别用于日期选择和多层级选择&#xff0c;提供了丰富的交互体验和便捷的数据…

CD4017 – 带解码输出的十进制计数器

CD4017 IC 是一个十进制计数器&#xff0c;它有 10 个输出&#xff0c;分别代表 0 到 9 的数字。计数器在&#xff08;14号引脚&#xff09;每个时钟脉冲上升时增加 1。计数器达到 9 后&#xff0c;它会在下一个时钟脉冲时从 0 重新开始。 引脚名称管脚 &#xff03;类型描述VD…

arthas命令使用

dashboard(线程、内存等环境概览) jvm&#xff08;JVM相关信息概览&#xff09; 1、RUNTIME&#xff08;系统运行环境JVM相关信息&#xff0c;运行时长等&#xff09; 2、CLASS-LOADING&#xff08;类加载信息&#xff09; 3、 COMPILATION&#xff08;编译信息&#xff09; 4…

Qt 网络编程实战

一.获取主机的网络信息 需要添加network模块 QT core gui network主要涉及的类分析 QHostInfo类 QHostInfo::localHostName() 获取本地的主机名QHostInfo::fromName(const QString &) 获取指定主机的主机信息 addresses接口 QNetworkInterface类 QNetworkInterfac…

Python——面向对象编程(类和对象)2

目录 私有属性和私有方法 01.应用场景及定义方式 02.伪私有属性和私有方法 继承 1.1继承的概念、语法和特点 1.继承的语法&#xff1a; 2.专业术语&#xff1a; 3.继承的传递性 1.2方法的重写 1.覆盖父类的方法 2.对父类方法进行扩展 关于super 1.3 父类的私有属性和…

机械拆装-基于Unity-装配功能的实现

目录 1. 装配场景的相机控制 2. 鼠标拖拽和旋转功能的实现 2.1 鼠标拖拽 2.2 物体旋转 3. 零件与装配位置的对应关系 4. 轴向装配的准备位置 5. 装配顺序的实现 5.1 标签提示 5.2 定义一个变量记录步骤数值 1. 装配场景的相机控制 开始装配功能时&#xff0c;需要将相机调…

vector与list的简单介绍

1. 标准库中的vector类的介绍&#xff1a; vector是表示大小可以变化的数组的序列容器。 就像数组一样&#xff0c;vector对其元素使用连续的存储位置&#xff0c;这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素&#xff0c;并且与数组中的元素一样高效。但与数…

1975react社区问答管理系统开发mysql数据库web结构node.js编程计算机网页源码

一、源码特点 react 社区问答管理系统是一套完善的完整信息管理类型系统&#xff0c;结合react.js框架和node.js后端完成本系统&#xff0c;对理解react node编程开发语言有帮助系统采用node框架&#xff08;前后端分离&#xff09;&#xff09;&#xff0c;系统具有完整的源…

6种ETL计算引擎介绍

目录 一、ETL计算引擎定义 二、ETL计算引擎的功能和特性 三、6种ETL计算引擎 1、MapReduce 2、Tez 3、Spark 4、Flink 5、ClickHouse 6、Doris 一、ETL计算引擎定义 ETL&#xff08;Extract, Transform, Load&#xff09;计算引擎是用于执行ETL过程中数据转换阶段的关键组件之一…

mac如何压缩视频大小不改变画质,mac怎么压缩视频软件

在数字时代&#xff0c;视频已成为信息传递和娱乐消遣的重要媒介。然而&#xff0c;视频带来的愉悦体验背后&#xff0c;是日益增长的存储和分享压力。大视频文件不仅占用大量存储空间&#xff0c;上传和下载也变得异常缓慢。那么&#xff0c;如何才能有效压缩视频&#xff0c;…

ERROR: No matching distribution found for numpy

1.原因&#xff1a; 出现这两行英文是因为原先输入pip install numpy的方式不安全&#xff0c;不被信任所以无法下载。 2.解决方法&#xff1a; 改成以下命令执行&#xff1a; pip install numpy -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun…

2025年中国国际新能源汽车技术零部件及服务展览会

中国国际新能源汽车技术零部件及服务展览会&#xff0c;从设计到制造、从使用到服务&#xff0c;精准“链”接新能源汽车全产业链的技术供应商和汽车制造商&#xff0c;专业面向新能源造车供应链的行业盛会。2024展会回顾&#xff1a;在展会的3天里&#xff0c;有62家车企核心供…

共享拼购:创新商业模式引领小用户基数下的销售奇迹“

在瞬息万变的商业蓝海中&#xff0c;一个新颖且深具潜力的策略正悄然改变着游戏规则&#xff0c;它巧妙地避开了传统路径的束缚&#xff0c;以微妙却深远的调整&#xff0c;开辟出了一条通往成功的独特航道。我的一位合作伙伴&#xff0c;正是这一策略的实践者&#xff0c;他在…

数字媒体技术基础之:DNG 文件

DNG&#xff08;Digital Negative&#xff09;文件是一种用于存储原始图像数据的文件格式&#xff0c;由 Adobe Systems 于2004年开发并推广。DNG 是一种开放的、非专利的原始图像格式&#xff0c;旨在为不同相机制造商提供一个统一的存储格式。DNG 文件保存了原始的、未处理的…

C++时区转换

#include <iostream> #include "cctz/civil_time.h" #include "cctz/time_zone.h"// 时区转换库 // https://github.com/google/cctzint test() {for (cctz::civil_day d(2016, 2, 1); d < cctz::civil_month(2016, 3); d) {std::cout << &…