直接贴代码,省市级数据来自自定义的仓库
index.tsx
import { View, PickerView, PickerViewColumn, Text } from "@tarojs/components";
import "./index.scss";
import React, { FC, useEffect, useState } from "react";
import Row from "@/component/Row";
import { useStores } from "@/store";
import { observer } from "mobx-react-lite";
import classNames from "classnames";
interface AddressPickerProps {
//父组件接值回调
onSure?: (address: [string, string][]) => void;
//组件初始值
defaultValue?: [string, string][];
}
const AddressPicker: FC<AddressPickerProps> = (props) => {
//接受一个回调的通知函数 和组件初始值
const { onSure, defaultValue } = props;
//连接仓库
const { userStore } = useStores();
const address = userStore.address;
//选定之后显示给用户的文本
const [adressText, setAdressText] = useState("");
//是否打开选择面板
const [pickerShow, setPickerShow] = useState(false);
//关闭面板函数
const onClosd = () => setPickerShow(false);
//地市级下标
const [state, setState] = useState([0, 0, 0]);
//监听三列滑动改变
const cityChange = (e) => {
if (e.detail.value[0] !== state[0]) {
//省份发生改变
return setState([e.detail.value[0], 0, 0]);
}
if (e.detail.value[1] !== state[1]) {
//市级发生改变
return setState([state[0], e.detail.value[1], 0]);
}
setState(e.detail.value);
};
//省市级数组 格式 [['100001',''北京],[‘100002’,'天津']]
const currentProvinces = Object.entries(address[86]);
//当前地级市数组
const currentCitys = Object.entries(address[currentProvinces[state[0]][0]]);
//当前县数组
const currentAreas = Object.entries(address[currentCitys[state[1]][0]]);
//返回最终结果
const handleSure = () => {
const tempAreaInfo = [
currentProvinces[state[0]],
currentCitys[state[1]],
currentAreas[state[2]],
];
//关闭弹框
onClosd();
//设置显示文字
setAdressText(tempAreaInfo.map((item) => item[1]).join(""));
//通知调用的组件 吧最终结果返回
onSure && onSure(tempAreaInfo);
};
//classNames 动态声明
const labelClasses = classNames("address-picker-primary", {
"address-picker-active": !!adressText,
});
const pickerClasses = classNames("address-picker-container", {
"show address-picker-container-active": pickerShow,
});
//完成初始化赋值
useEffect(() => {
if (defaultValue) {
//如果传入初始值
const provinceCode = defaultValue[0][0]; //省级key
const cityCode = defaultValue[1][0]; //市级key
const areaCode = defaultValue[2][0]; //省级key
//省级下标
const currentProvincesIndex = currentProvinces.findIndex(
(v) => v[0] === provinceCode
);
//市级下标
const currentCityIndex = Object.entries(address[provinceCode]).findIndex(
(v) => v[0] === cityCode
);
//县级下标
const currentAreaIndex = Object.entries(address[cityCode]).findIndex(
(v) => v[0] === areaCode
);
//对齐下标
setState([currentProvincesIndex, currentCityIndex, currentAreaIndex]);
//对齐展示文字
setAdressText(defaultValue.map((item) => item[1]).join(""));
}
}, []);
return (
<View>
<Row onClick={() => setPickerShow(true)} showRightArrow title="所在地区">
<Text className={labelClasses}>{adressText || "请选择地区"}</Text>
</Row>
<View onClick={() => onClosd()} className={pickerClasses}>
<View
onClick={(event) => event.stopPropagation()}
className="picker-content"
>
<View className="dialog-header">
<View onClick={() => onClosd()} className="dialog-button cancel">
取消
</View>
<View className="dialog-title">请选择地区</View>
<View className="dialog-button" onClick={handleSure}>
确定
</View>
</View>
<PickerView
onChange={cityChange}
value={state}
className="picker-view-wrap"
>
<PickerViewColumn>
{currentProvinces.map((province, index) => {
return (
<View className="picker-item" key={index}>
{province[1]}
</View>
);
})}
</PickerViewColumn>
<PickerViewColumn>
{currentCitys.map((city, index) => {
return (
<View className="picker-item" key={index}>
{city[1]}
</View>
);
})}
</PickerViewColumn>
<PickerViewColumn>
{currentAreas.map((area, index) => {
return (
<View className="picker-item" key={index}>
{area[1]}
</View>
);
})}
</PickerViewColumn>
</PickerView>
</View>
</View>
</View>
);
};
export default observer(AddressPicker);
index.scss
@keyframes back {
0% {
background: rgba(255, 255, 255, 0);
opacity: 0;
}
100% {
background: rgba(0, 0, 0, 0.7);
opacity: 1;
}
}
@keyframes up
{
0% { transform: translateY(600px);opacity: 0; }
100% { transform: translateY(0);opacity: 1; }
}
.address-picker-container::after{
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
background: rgba(0, 0, 0, 1);
opacity: 0;
transition: opacity .3s ease-in-out;
}
.address-picker-container-active::after{
opacity: 0.7;
// animation-fill-mode: forwards;
}
.address-picker-container {
width: 100%;
height: 100vh;
display: flex;
z-index: 12;
// background: rgba(0, 0, 0, 0.7);
flex-direction: column;
justify-content: center;
align-items: center;
position: fixed;
bottom: 0px;
left: 0px;
visibility: hidden;
&.show {
visibility: visible;
.picker-content {
transform: translateY(0);
opacity: 1;
// transform: translateY(200%);
// transition: all .4s ease-in-out;
//animation: up .3s ease-in-out forwards;
}
}
}
.picker-content {
border-top-left-radius: 32px;
border-top-right-radius: 32px;
position: absolute;
height: 660px;
z-index: 999;
width: 100%;
bottom: 0;
background-color: #fff;
transition: all .3s ease-in-out;
transform: translateY(600px);
opacity: 0;
.picker-view-wrap {
width: 100%;
height: 500px;
margin-top: -50px;
}
}
.picker-item {
line-height: 70px;
font-size: 30px;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
}
.dialog-header {
width: 100%;
// background: #ededed;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 30px;
.dialog-title {
color: #2E2E2E;
font-size: 34px;
}
.dialog-button {
display: inline-block;
text-align: center;
font-size: 34px;
color: #846B57;
padding: 50px;
&.cancel {
color: #999999;
}
}
}
.address-picker-primary{
padding-right: 22px;
color: #999999;
}
.address-picker-active{
color: #262626;
}
开始使用
import AddressPicker from "@/component/SelectCity";
<AddressPicker
defaultValue={[
["340000", "安徽省"],
["340700", "铜陵市"],
["340705", "铜官区"],
]}
onSure={(e) => console.log(e)}
/>
//defaultValue可不传
原来还可以这样