基于react-native-wheel-pick的三级地址选择

效果示例图

在这里插入图片描述

安装依赖

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 (
    <>
      <Modal visible={visible} animationType="fade" transparent>
        <View style={styles.pickerWrap}>
          <View style={styles.pickerBlock}>
            <View style={{height: pxToPd(24)}}></View>
            <View style={styles.pickerContent}>
              {/* 头部 */}
              <View style={styles.pickerHeader}>
                <View style={styles.cancelBtn}>
                  <TouchableOpacity onPress={cancelHandle}>
                    <Text style={styles.cancelText}>取消</Text>
                  </TouchableOpacity>
                </View>
                <View style={styles.confirmBtn}>
                  <TouchableOpacity onPress={confirmHandle}>
                    <Text style={styles.confirmText}>确认</Text>
                  </TouchableOpacity>
                </View>
              </View>
              {/* 内容 */}
              <View style={styles.pickerBody}>
                {/* 省 */}
                <View style={styles.provinceWrap}>
                  <Picker
                    style={{
                      backgroundColor: 'white',
                      width: '100%',
                    }}
                    itemStyle={{fontSize: 12}}
                    selectedValue={provID}
                    pickerData={province}
                    onValueChange={value => {
                      changeProvinceHandle(value);
                    }}
                  />
                </View>
                {/* 市 */}
                <View style={styles.cityWrap}>
                  {isPickerReset ? (
                    <Picker
                      style={{
                        backgroundColor: 'white',
                        width: '100%',
                      }}
                      itemStyle={{fontSize: 12}}
                      selectedValue={cityID}
                      pickerData={cityData}
                      onValueChange={value => {
                        changeCityHandle(value);
                      }}
                    />
                  ) : (
                    ''
                  )}
                </View>
                {/* 区 */}
                <View style={styles.countyWrap}>
                  {isCountyReset ? (
                    <Picker
                      style={{
                        backgroundColor: 'white',
                        width: '100%',
                      }}
                      itemStyle={{fontSize: 12}}
                      selectedValue={countyID}
                      pickerData={county}
                      onValueChange={value => {
                        changeCountyHandle(value);
                      }}
                    />
                  ) : (
                    ''
                  )}
                </View>
              </View>
            </View>
            <View style={{height: pxToPd(24)}}></View>
          </View>
        </View>
      </Modal>
    </>
  );
});
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,
        });
      },
    });
  };

<PickerAddressComponent ref={addressRef} />

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;
};

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值