仿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,一经查实,立即删除!

相关文章

第二十六章 生成器(generator)(Python)

文章目录 前言一、生成器函数 前言 在 Python 中&#xff0c;使用了 yield 的函数被称为生成器&#xff08;generator&#xff09; yield 是一个关键字&#xff0c;用于定义生成器函数&#xff0c;生成器函数是一种特殊的函数&#xff0c;可以在迭代过程中逐步产生值&#xff…

jsqlparse工具拦截sql处理和拓展

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

网络扫描工具Nmap,用于发现网络中的主机和服务

Nmap 是一个非常强大的网络扫描工具&#xff0c;可以用于发现网络中的主机和服务。使用 Nmap 可以获取关于目标系统的各种信息&#xff0c;包括开放端口、操作系统版本、服务版本等。以下是如何使用 Nmap 以及一些常见的用例&#xff1a; 安装 Nmap 在 Ubuntu 22.04 上安装 N…

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

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…

校验是否是合法日期字符串正则

常用的ui组件不支持日月的这种形式&#xff0c;产品提成要用input框的形式来做&#xff0c;且对输入字符串是否符合时间格式做校验&#xff0c;写起来还是很麻烦的&#xff0c;记录一下以后备用。 <script> /*** 校验是否是合法日期字符串* 支持格式&#xff1a;* …

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

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

C++ STL容器:序列式容器-队queue,deque

摘要&#xff1a; CC STL&#xff08;Standard Template Library&#xff0c;标准模板库&#xff09;在C编程中的重要性不容忽视&#xff0c;STL提供了一系列容器、迭代器、算法和函数对象&#xff0c;这些组件极大地提高了C程序的开发效率和代码质量。 STL 容器 分为 2 大类 …

Oracle数据库中导出多个表

要在Oracle数据库中导出多个表&#xff0c;可以使用exp&#xff08;Export&#xff09;工具或expdp&#xff08;Data Pump Export&#xff09;工具。下面是两种方法的详细说明&#xff1a; 1. 使用exp工具导出多个表&#xff1a; exp是Oracle的传统导出工具&#xff0c;它允许…

一文搞懂到底什么是 AQS

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

树的笔记()

文章目录 菜单数据库设计什么结构便于使用 树结构是应用非常广泛的结构&#xff0c;甚至可以说无处不在。 电脑里的文件夹是不是树结构&#xff0c;省市区县镇乡村是不是树结构&#xff0c;菜单是不是树结构&#xff0c;军队是不是树结构&#xff0c;职位是不是树结构。。。太多…

ES module 工作原理浅谈

ES module&#xff08;ECMAScript module&#xff09;的工作过程涉及三个主要步骤&#xff1a;获取、解析和实例化。 获取步骤涉及获取所有需要的模块。当JavaScript引擎遇到import语句时&#xff0c;它首先查看module map是否已经有了一个与URL匹配的条目。如果没有&#xff…

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…

python输出日志out.log相关问题(缓存机制)

现象&#xff1a;nohup python total_test619.py > out.log 2>&1 &&#xff0c;total_test619.py功能如下&#xff0c;首先计算13的值&#xff0c;然后将该值print出来&#xff0c;之后等待5分钟&#xff0c;重新运行之前的函数&#xff0c;输出结果&#xff0c;…

Coding:小写一个debugfs

目录 事先检查 开干 撸代码 上一次整活还是在上一个月&#xff0c;写了一个简单的module并且熟悉了module的挂载查看和卸载。这一次我们自然玩一个大的&#xff0c;就是利用linux的debugfs API写一个调试文件系统。 事实上&#xff0c;底层的API全写好了&#xff0c;我们就是…

arthas命令使用

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

TimerManager和Timer

在RTSP服务器中需要一个定时器来定时发送音频帧和视频帧。音频帧每隔23ms发送一帧&#xff0c;视频帧每隔40ms发一帧。 因此需要两个定时器来定时发送&#xff0c;此时我们就需要用到一个TimerManager来管理Timer。 在TimerManager类中我们需要创建定时器文件描述符&#xff…

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 父类的私有属性和…