![](https://i-blog.csdnimg.cn/blog_migrate/a38981d6399e5129e7a6c465050ef983.png)
根据 antd 的 Cascader 和 Select 组件进行进一步的封装,按需处理好所需要的省、市、区和街道的数据,然后给到组件就好了。这里用到的技术栈是:react,hooks 和 ts;
使用方法如下
import AreaCascader from '@/components/AreaCascader';
import type { areaItemType } from '@/components/AreaCascader';
import { useState, useMemo } from 'react';
type AddressInfoType = {
// ... 一些别的信息
provinceName: string; // 省
cityName: string; // 市
countyName: string; // 区
streetName: string; // 街道
nationalCode: string; // // 地区码
};
export default function TestPage() {
// 需要的一些地址信息(其中包括省、市、区、街道、地区码等)
const [addressInfo, setAddressInfo] = useState<AddressInfoType>({
// ... 一些别的信息
provinceName: '',cityName: '',countyName: '',streetName: '',nationalCode: ''
});
const { provinceName, cityName, countyName, streetName } = addressInfo;
// 选中的值 使用的时候用 useMemo 记录一下
const areaValue = useMemo(
() => [provinceName, cityName, countyName, streetName],
[provinceName, cityName, countyName, streetName],
);
// onChange 的回调方法
const areaChange = (e?: string[], e2?: areaItemType[]) => {
console.log(e, e2);
setAddressInfo((v) => ({
...v,
provinceName: e?.[0] ?? '',
cityName: e?.[1] ?? '',
countyName: e?.[2] ?? '',
streetName: e?.[3] ?? '',
// 由于业务需求,我这里是获取到区的地区码即可。
nationalCode: e2?.[2]?.code ?? '',
}));
};
return (
<div style={{width: '300px'}}>
<AreaCascader
type="street"
value={areaValue}
onChange={areaChange}
/>
</div>
);
}
props说明
type CascaderType = 'province' | 'city' | 'area' | 'street';
type PropsType = {
type?: CascaderType;
value: string[] | string;
placeholder?: string;
onChange: (e?: string[], option?: areaItemType[]) => void;
};
type:
- province:只有省
- city:只有省市
- area:只有省市区(不传或传其它,默认选中该值)
- street:省市区街道都有
value: 当前选中的值,当只有 type 为 province 时传入字符串即可,其它情况传入对应的地区字符串数组。
onChange: (value, selectedOptions) => void,第一个参数是返回选中的值(一个字符串数组),第二个参数返回选中的值还有地区码。
组件源码
import { Cascader, Select } from 'antd';
import { useEffect, useState } from 'react';
const { Option } = Select;
export type areaItemType = {
code: string;
name: string;
children?: areaItemType[];
};
type CascaderType = 'province' | 'city' | 'area' | 'street';
type PropsType = {
type?: CascaderType;
value: string[] | string;
placeholder?: string;
onChange: (e?: string[], option?: areaItemType[]) => void;
};
export default ({
value,
type = 'area',
placeholder = '请选择省市区',
onChange,
}: PropsType) => {
const [options, setOptions] = useState<areaItemType[]>();
useEffect(() => {
const getData = async () => {
let data;
if (type === 'street') {
// 省市区街道 该文件1.9m~~
data = (await import('./areas-streets.json')).default;
} else {
data = (await import('./areas.json')).default;
}
switch (type) {
// 省
case 'province': {
const list = JSON.parse(JSON.stringify(data)).map(
(item: areaItemType) => {
delete item.children;
return item;
},
);
setOptions(list);
break;
}
// 省市
case 'city': {
const list = JSON.parse(JSON.stringify(data)).map(
(item: areaItemType) => {
item.children?.forEach((item2: areaItemType) => {
if (item2.children) {
delete item2.children;
}
});
return item;
},
);
setOptions(list);
break;
}
default: {
setOptions(data);
}
}
};
if (type) {
getData();
}
}, [type]);
if (type == 'province') {
// 只有省的下拉框
return (
<Select
value={value as string}
onChange={(e, option) => {
const o = option as DefaultOptionType;
onChange([e], [{ code: o.key, name: o.value as string }]);
}}
>
{options?.map(({ name, code }: areaItemType) => (
<Option key={code} value={name}>
{name}
</Option>
))}
</Select>
);
} else {
// 省市区街道的下拉框
const val = value as string[];
return (
<Cascader
value={val?.some((v) => v) ? val : ['']}
fieldNames={{ label: 'name', value: 'name', children: 'children' }}
expandTrigger="hover"
options={options}
placeholder={placeholder}
onChange={(e, option) => {
onChange(e as string[], option as unknown as areaItemType[]);
}}
style={{width: '100%'}}
/>
);
}
};
数据来源:https://github.com/modood/Administrative-divisions-of-China
![](https://i-blog.csdnimg.cn/blog_migrate/ed8ea68d947d9310e568652a3855893d.png)
省市区 json 数据:https://github.com/modood/Administrative-divisions-of-China/blob/master/dist/pca-code.json
省市区街道 json 数据:https://github.com/modood/Administrative-divisions-of-China/blob/master/dist/pcas-code.json
主要是这两份数据,文件比较大,特别是包括街道那个,差不多有1.9m,建议不要学我丢本地项目里面了。