基于react-native-wheel-pick的三级地址选择
-
- 效果示例图
- 安装依赖
- 封装组件PickerAddressComponent
- 使用组件
- device.js
效果示例图
安装依赖
React Native >= 0.60+
https://www.npmjs.com/package/react-native-wheel-pick
1.安装
npm install react-native-wheel-pick --save-dev --legacy-peer-deps
npm install @react-native-picker/picker --save-dev --legacy-peer-deps
npm install @react-native-community/datetimepicker --save-dev --legacy-peer-deps
封装组件PickerAddressComponent
import React, {
forwardRef,
useImperativeHandle,
useState,
useEffect,
} from 'react';
import {Modal, StyleSheet, View, TouchableOpacity, Text} from 'react-native';
import {pxToPd} from '../../common/js/device';
//下拉组件
import {Picker} from 'react-native-wheel-pick';
const PickerAddressComponent = forwardRef((props, ref) => {
const [isPickerReset, setIsPickerReset] = useState(true);
const [isCountyReset, setIsCountyReset] = useState(true);
const [visible, setVisible] = useState(false);
const [options, setOptions] = useState({
zoneId: null, //省ID
cityId: null, //市ID
countyId: null, //区ID
success: null,
});
//临时地址数据
const [addressList, setAddressList] = useState([]);
//省
const [provID, setProvID] = useState(null);
const [province, setProvince] = useState([]);
//市
const [cityID, setCityID] = useState(null);
const [cityData, setCity] = useState([]);
//区
const [countyID, setCountyID] = useState(null);
const [county, setCounty] = useState([]);
//详细地址
const [address, serAddress] = useState('');
const fetchData = async () => {
try {
const response = await fetch(
`https://xxxxx.file.myqcloud.com/address.json`,
);
const data = await response.json();
const result = data.res;
setAddressList(result);
initAddressHandle(result);
// 在这里处理接口返回的数据
} catch (error) {
console.error(error);
// 处理请求错误
setProvince([]);
setCity([]);
setCounty([]);
setProvID(null);
setCityID(null);
setCountyID(null);
}
};
const initAddressHandle = (data, zoneId, cityId, countyId) => {
const getProvince = (data, id) => {
const tempProvince = data.map(element => ({
value: element.id,
label: element.name,
code: element.code,
}));
setProvince(tempProvince);
setProvID(id);
setCity([]);
setCounty([]);
const filterList = data.find(item => item.id === id);
if (filterList && filterList.cityList.length > 0) {
setCityID(null);
setCountyID(null);
getCity(filterList.cityList, cityId || filterList.cityList[0].id);
} else {
resetCityAndCounty();
}
};
const getCity = (data, id) => {
if (data.length > 0) {
const tempCity = data.map(element => ({
value: element.id,
label: element.name,
code: element.code,
}));
setCity(tempCity);
setCityID(id);
setCounty([]);
const filterList = data.find(item => item.id === id);
if (filterList && filterList.areaList.length > 0) {
getCounty(filterList.areaList, countyId || filterList.areaList[0].id);
} else {
resetCityAndCounty();
}
} else {
resetCityAndCounty();
}
};
const getCounty = (data, id) => {
if (data.length > 0) {
const tempCounty = data.map(element => ({
value: element.id,
label: element.name,
code: element.code,
}));
setCounty(tempCounty);
setCountyID(id);
} else {
resetCounty();
}
};
const resetCityAndCounty = () => {
setCity([]);
setCounty([]);
setCityID(null);
setCountyID(null);
};
const resetCounty = () => {
setCounty([]);
setCountyID(null);
};
getProvince(data, zoneId || data[0].id);
};
//改变省份选择
const changeProvinceHandle = id => {
setProvID(id);
setCityID(null);
setCountyID(null);
const tempAddressData = [...addressList];
initAddressHandle(tempAddressData, id, null, null);
setIsPickerReset(false);
setTimeout(() => {
setIsPickerReset(true);
}, 0);
};
//改变市选择
const changeCityHandle = id => {
setCityID(id);
setCountyID(null);
const tempAddressData = [...addressList];
initAddressHandle(tempAddressData, provID, id, null);
setIsCountyReset(false);
setTimeout(() => {
setIsCountyReset(true);
}, 0);
};
//改变区选择
const changeCountyHandle = id => {
console.log('[区]', id);
setCountyID(id);
const tempAddressData = [...addressList];
initAddressHandle(tempAddressData, provID, cityID, id);
};
//关闭弹出框
const hide = params => {
setVisible(false);
options.success({
zoneId: params.zoneId, //省ID
cityId: params.cityId, //市ID
countyId: params.countyId, //区ID
address: getAddressDetail(params.zoneId, params.cityId, params.countyId),
});
};
//展示地址选择
const show = params => {
setOptions({
...options,
zoneId: params.zoneId ? params.zoneId : null, //省ID
cityId: params.cityId ? params.cityId : null, //市ID
countyId: params.countyId ? params.countyId : null, //区ID
success: params.success,
});
initAddressHandle(
addressList,
params.zoneId ? params.zoneId : null,
params.cityId ? params.cityId : null,
params.countyId ? params.countyId : null,
);
setVisible(true);
};
//点击取消
const cancelHandle = () => {
hide(options);
};
//点击确认
const confirmHandle = () => {
hide({
zoneId: provID,
cityId: cityID,
countyId: countyID,
});
};
//根据省市区id,获取详细地址
const getAddressDetail = (zoneId, cityId, countyId) => {
const provinceData = addressList.find(item => item.id === zoneId);
let tempAddress = provinceData ? provinceData.name : '';
if (provinceData && cityId) {
const cityData = provinceData.cityList.find(item => item.id === cityId);
tempAddress += cityData ? ` ${cityData.name}` : '';
if (cityData && countyId) {
const countyData = cityData.areaList.find(item => item.id === countyId);
tempAddress += countyData ? ` ${countyData.name}` : '';
}
}
return tempAddress;
};
useImperativeHandle(ref, () => ({
show,
}));
useEffect(() => {
console.log('[地址组件]');
fetchData();
}, []);
return (
<>
{/* 头部 */}
取消
确认
{/* 内容 */}
{/* 省 */}
{
changeProvinceHandle(value);
}}
/>
{/* 市 */}
{isPickerReset ? (
{
changeCityHandle(value);
}}
/>
) : (
''
)}
{/* 区 */}
{isCountyReset ? (
{
changeCountyHandle(value);
}}
/>
) : (
''
)}
>
);
});
const styles = StyleSheet.create({
pickerWrap: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
position: 'relative',
},
pickerBlock: {
borderColor: '#dcdcdc',
borderWidth: pxToPd(1),
borderStyle: 'solid',
borderBottomWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 0,
width: '100%',
height: pxToPd(540),
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
backgroundColor: '#fff',
},
pickerContent: {
width: '91.47%',
marginLeft: '4.265%',
},
pickerHeader: {
width: '100%',
height: pxToPd(70),
flexDirection: 'row',
justifyContent: 'space-between',
},
cancelBtn: {
borderRadius: pxToPd(35),
width: pxToPd(150),
height: pxToPd(70),
backgroundColor: '#f5f5f5',
overflow: 'hidden',
},
cancelText: {
color: '#666',
fontSize: pxToPd(34),
fontWeight: '400',
width: pxToPd(150),
height: pxToPd(70),
lineHeight: pxToPd(70),
textAlign: 'center',
},
confirmBtn: {
borderRadius: pxToPd(35),
width: pxToPd(150),
height: pxToPd(70),
backgroundColor: '#FF5B23',
overflow: 'hidden',
},
confirmText: {
color: '#fff',
fontSize: pxToPd(34),
fontWeight: '400',
width: pxToPd(150),
height: pxToPd(70),
lineHeight: pxToPd(70),
textAlign: 'center',
},
pickerBody: {
width: '100%',
marginTop: pxToPd(12),
flexDirection: 'row',
},
provinceWrap: {
width: pxToPd(228),
},
cityWrap: {
width: pxToPd(228),
},
countyWrap: {
width: pxToPd(228),
},
});
export default PickerAddressComponent;
使用组件
// 三级地址选择
import PickerAddressComponent from '../../componets/PickerAddressComponent';
const [queryParams, setQueryParams] = useState({
zoneId: null, //省ID
cityId: null, //市ID
countyId: null, //区ID
tempAddress: '',
});
//选择地址
const addressRef = useRef(null);
const selectAddressHandle = () => {
addressRef.current.show({
zoneId: queryParams.zoneId, //省ID
cityId: queryParams.cityId, //市ID
countyId: queryParams.countyId, //区ID
success: res => {
console.log('[]', res);
setQueryParams({
...queryParams,
zoneId: res.zoneId,
cityId: res.cityId,
countyId: res.countyId,
tempAddress: res.address,
});
},
});
};
device.js
import {Dimensions, StatusBar, Platform} from 'react-native';
//RN中的尺寸单位为dp,设计稿的单位为px
// 获取屏幕尺寸
const windowDimensions = Dimensions.get('window');
//设备宽度,单位pd
const deviceWidthDp = windowDimensions.width;
//设备高度
const windowHeight = windowDimensions.height;
// 获取状态栏高度
const statusBarCurrentHeight =
Platform.OS === 'android' ? StatusBar.currentHeight : 20;
//设计稿宽度(这里为750px),单位px
const uiWidthPx = 750;
//px转pd(设计稿中的px转RN中的dp)
//计算公式:设计稿元素宽度(px)/设计稿总宽度(px)=元素的宽度(dp)/屏幕的总宽度(dp)
export const pxToPd = uiElePx => {
return (uiElePx * deviceWidthDp) / uiWidthPx;
};
//状态栏高度
export const statusBarHeight = () => {
return statusBarCurrentHeight;
};
// 计算应用程序窗口的高度
// 获取导航栏高度(如果有的话) navigationBarHeight = 0; // 设置默认值
export const appWindowHeight = (navigationBarHeight = 0) => {
return windowHeight - navigationBarHeight;
};