taro-ui实现省市区三级联动

因taro-ui没有省市区三级联动,所以我们利用它提供的Picker 实现多列选择器。

<Picker
            mode="multiSelector" // 多列选择
            onChange={this.onChange} // change事件
            onColumnChange={this.onColumnChange} // 某列改变的事件
            range={rangeData} //需要展示的数据
            value={rangeKey} // 选择的下标
          >
            <View className="picker">
              <Text className="label">所在地址:</Text>
              {formData.province && (
                <Text>
                  {formData.province}
                  {formData.city}
                  {formData.country}
                </Text>
              )} // 主要是数据回显加的代码,
              {!formData.province && (
                <Text className="placeholder">请选择省/市/区</Text>
              )}
            </View>
          </Picker>

上述代码其实taro-ui官方文档都有具体的事例,这里就不多解释了。

相信每个的省市区结构都不一样,现在贴一部分自己项目的省市区结构

[{
	provinceName: '北京市',
	provinceCode: '11',
	cities: [
	{
	cityName: '市辖区',
	cityCode: '1101',
	countries: [
		{
			countryCode: "110101"
			countryName: "东城区"
		}
		]
	}
	]
}]

现在开始处理数据,因为rangeData是所有数据,省市区,我们需要把数据转换成[‘省’, ‘市’, ‘区’]。

handleCityData = key => {
    // 处理数据。
    let provinceList = new Array(); // 省
    let cityList = new Array(); // 市
    let areaList = new Array(); // 区
    let { addressData } = this.state;
    for (let i = 0; i < addressData.length; i++) {
      // 获取省
      let province = addressData[i];
      provinceList.push(province.provinceName);
    }
    if (addressData[key[0]].cities && addressData[key[0]].cities.length > 0) {
      for (let i = 0; i < addressData[key[0]].cities.length; i++) {
        // 获取对应省下面的市
        let city = addressData[key[0]].cities[i];
        cityList.push(city.cityName);
      }
    }
    for (
      let i = 0;
      i < addressData[key[0]].cities[key[1]].countries.length;
      i++
    ) {
      // 获取市下面对应区
      let country = addressData[key[0]].cities[key[1]].countries[i];
      areaList.push(country.countryName);
    }
    // }
    let newRange = new Array();
    newRange.push(provinceList);
    newRange.push(cityList);
    newRange.push(areaList);
    this.setState({
      rangeData: newRange, // 省市区所有的数据
      rangeKey: key // key是多列选择器需要展示的下标,因为是初始化,所以我们传入[0,0,0]
    });
  };

数据处理代码有点丑,欢迎大家提意见。因babel没升级到7版本,所以if判断有点繁琐。

数据处理完了之后,我们需要开始处理每列的值改变,数据联动了,那么我们需要列联动事件。

onColumnChange = e => {
    let { rangeKey } = this.state;
    let changeColumn = e.detail;
    let { column, value } = changeColumn;
    switch (column) { // 根据改变不同的列,来显示不同的数据
      case 0:
        this.handleCityData([value, 0, 0]);
        break;
      case 1:
        this.handleCityData([rangeKey[0], value, 0]);
        break;
      case 2:
        this.handleCityData([rangeKey[0], rangeKey[1], value]);
        break;
    }
  };

到这里的话,就基本实现了省市区三级联动。

下面说一哈,省市区数据回显的代码,不需要的朋友也可以了解一哈。
数据回显,其实很简单,只要找到对应的省市区的下标,就可以回显了。下面是具体实现代码:

getRangeKey = data => {
    // 详情的时候获取对应的展示位置
    let { addressData } = this.state;
    let splitData = data.addressDescription.split("|");

    let getAddress = {
      province: splitData[0],
      city: splitData[1],
      country: splitData[2]
    };
    this.setState({
      formData: getAddress
    });
    let provinceIndex = 0;
    let cityIndex = 0;
    let countryIndex = 0;
    for (let i = 0; i < addressData.length; i++) {
      let province = addressData[i];
      if (province.provinceName === getAddress.province) {
        provinceIndex = i;
        for (let j = 0; j < province.cities.length; j++) {
          let city = province.cities[j];
          if (city.cityName === getAddress.city) {
            cityIndex = j;
            for (let k = 0; k < city.countries.length; k++) {
              let country = city.countries[k];
              if (country.countryName === getAddress.country) {
                countryIndex = k;
                break;
              }
            }
            break;
          }
        }
        break;
      }
    }
    let rangeKey = new Array();
    rangeKey.push(provinceIndex);
    rangeKey.push(cityIndex);
    rangeKey.push(countryIndex);
    this.handleCityData(rangeKey);
  };

通过上面的循环找出对应省市区的下标,就可以实现省市区的数据回显。

噢,还忘了多列选择器的change事件,这个的话,根据自己项目需要返回的是code还是name,这块就自己处理了,我这边讲的主要是省市区的三级联动。
我是把省市区写成一个组件,然后在父节点传入对应的数据以及事件就可以在一个项目中多次用到了。

下面是该组件的所有代码

import Taro, { Component } from "@tarojs/taro";
import { View, Text, Image, ScrollView, Picker } from "@tarojs/components";
import { connect } from "@tarojs/redux";
import * as actions from "@actions/address";
// import { dispatchCartNum } from '@actions/cart';
import "./index.scss";

@connect(state => state.address, { ...actions })
class ChangeCity extends Component {
  static defaultProps = {
    detailAddress: {}
  };
  constructor(props) {
    super(props);
    this.state = {
      addressData: [],
      rangeKey: [0, 0, 0],
      rangeData: [[], [], []],
      formData: {
        province: "",
        city: "",
        country: ""
      }
    };
  }

  componentDidMount() {
    this.getAddress();
  }
  getAddress = () => {
    this.props.dispatchAddressChina().then(res => {
      let addressData = [...res.data];
      this.setState(
        {
          addressData: addressData
        },
        () => {
          let { detailAddress } = this.props;
          if (!detailAddress.province) {
            this.handleCityData([0, 0, 0]);
          } else {
            this.getRangeKey(detailAddress);
          }
        }
      );
    });
  };
  getRangeKey = data => {
    // 详情的时候获取对应的展示位置
    let { addressData } = this.state;
    let splitData = data.addressDescription.split("|");

    let getAddress = {
      province: splitData[0],
      city: splitData[1],
      country: splitData[2]
    };
    this.setState({
      formData: getAddress
    });
    let provinceIndex = 0;
    let cityIndex = 0;
    let countryIndex = 0;
    for (let i = 0; i < addressData.length; i++) {
      let province = addressData[i];
      if (province.provinceName === getAddress.province) {
        provinceIndex = i;
        for (let j = 0; j < province.cities.length; j++) {
          let city = province.cities[j];
          if (city.cityName === getAddress.city) {
            cityIndex = j;
            for (let k = 0; k < city.countries.length; k++) {
              let country = city.countries[k];
              if (country.countryName === getAddress.country) {
                countryIndex = k;
                break;
              }
            }
            break;
          }
        }
        break;
      }
    }
    let rangeKey = new Array();
    rangeKey.push(provinceIndex);
    rangeKey.push(cityIndex);
    rangeKey.push(countryIndex);
    this.handleCityData(rangeKey);
    this.setState({
      rangeKey: rangeKey
    });
  };
  handleCityData = key => {
    // 处理数据
    let provinceList = new Array(); // 省
    let cityList = new Array(); // 市
    let areaList = new Array(); // 区
    let { addressData } = this.state;
    for (let i = 0; i < addressData.length; i++) {
      // 获取省
      let province = addressData[i];
      provinceList.push(province.provinceName);
    }
    if (addressData[key[0]].cities && addressData[key[0]].cities.length > 0) {
      for (let i = 0; i < addressData[key[0]].cities.length; i++) {
        // 获取对应省下面的市
        let city = addressData[key[0]].cities[i];
        cityList.push(city.cityName);
      }
    }
    for (
      let i = 0;
      i < addressData[key[0]].cities[key[1]].countries.length;
      i++
    ) {
      // 获取市下面对应区
      let country = addressData[key[0]].cities[key[1]].countries[i];
      areaList.push(country.countryName);
    }
    // }
    let newRange = new Array();
    newRange.push(provinceList);
    newRange.push(cityList);
    newRange.push(areaList);
    this.setState({
      rangeData: newRange,
      rangeKey: key
    });
  };
  onChange = e => {
    let { value } = e.detail;
    this.getAddressName(value);
  };
  getAddressName = value => {
    // 这里是转化用户选择的地址数据
    let { addressData } = this.state;
    let formData = {
      province: "",
      city: "",
      country: ""
    };
    let payload = {
      province: "",
      city: "",
      country: ""
    };
    if (addressData[value[0]]) {
      formData.province = addressData[value[0]].provinceName; // 省名称
      payload.province = addressData[value[0]].provinceCode; // 省code
      if (
        addressData[value[0]].cities &&
        addressData[value[0]].cities[value[1]]
      ) {
        formData.city = addressData[value[0]].cities[value[1]].cityName;
        payload.city = addressData[value[0]].cities[value[1]].cityCode;
        if (
          addressData[value[0]].cities[value[1]].countries &&
          addressData[value[0]].cities[value[1]].countries[value[2]]
        ) {
          formData.country =
            addressData[value[0]].cities[value[1]].countries[
              value[2]
            ].countryName;
          payload.country =
            addressData[value[0]].cities[value[1]].countries[
              value[2]
            ].countryCode;
        }
      }
    }
    // console.log(formData, "formData");
    this.setState({
      formData: formData
    });
    this.props.onChangeAddress(payload, formData);
  };
  onColumnChange = e => {
    let { rangeKey } = this.state;
    let changeColumn = e.detail;
    let { column, value } = changeColumn;
    switch (column) {
      case 0:
        this.handleCityData([value, 0, 0]);
        break;
      case 1:
        this.handleCityData([rangeKey[0], value, 0]);
        break;
      case 2:
        this.handleCityData([rangeKey[0], rangeKey[1], value]);
        break;
    }
  };
  render() {
    const { formData, rangeData, rangeKey } = this.state;
    return (
      <View className="change-city">
        <View>
          <Picker
            mode="multiSelector"
            onChange={this.onChange}
            onColumnChange={this.onColumnChange}
            range={rangeData}
            value={rangeKey}
          >
            <View className="picker">
              <Text className="label">所在地址:</Text>
              {formData.province && (
                <Text>
                  {formData.province}
                  {formData.city}
                  {formData.country}
                </Text>
              )}
              {!formData.province && (
                <Text className="placeholder">请选择省/市/区</Text>
              )}
            </View>
          </Picker>
        </View>
      </View>
    );
  }
}
export default ChangeCity;

样式的话自己处理一哈就可以了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值