您现在的位置是:首页 > 正文

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

2024-04-01 00:40:17阅读 3

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

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

网站文章

  • 9.23动手动脑

    9.23动手动脑

    方法返回类型不同,函数值相同,传参类型不同,这是方法的重载。转载于:https://www.cnblogs.com/mac-13/p/11595563.html

    2024-04-01 00:40:09
  • Android关键知识点详解

    1. Activity 2. Service 3. BroadcastReceiver 4. ContentProvider 5. Intent Android应用程序使用Java做为开发语言。aapt工具把编译后的Java代码连同其它应用程序需要的数据和资源文件一起打包到一个Android包文件中,这个文件使用.apk做为扩展名,它是分发应用程序并安装到移动设备的媒介,用户只

    2024-04-01 00:40:02
  • 云计算如何助力环保事业智慧升级?

    近年来,全球多地自然灾害频发,气候变暖问题愈发严重,一旦到达气候临界点,生态环境变化将不可逆转,环保工作刻不容缓。随着以云计算为代表的新技术的快速发展,环保工作逐渐实现了“智慧+”。“智慧环保”是“数...

    2024-04-01 00:39:37
  • css学习5:选择器简明参考

    选择器 说明 * 选取所有元素 选取指定类型的元素 . 选取指定类的元素 # 选取id属性为指定值的元素 [attr] 选取定义了attr属性,且属性值任意的元素 [attr=“val”] 选取定义了...

    2024-04-01 00:39:31
  • word自带参考文献标注功能—以word2013为例

    word自带参考文献标注功能—以word2013为例

    今天调整论文的参考文献,发现文献标注确实很麻烦,就上网搜了一下参考文献的自动标注功能,发现了一名博主的文章写的很好,然后笔者根据自己的使用经验进行了一些补充,这里分享给大家。以word2013版为例,进行说明,其他版本的选项位置可能不一样,但是操作应该大同小异。word参考文献标注功能与手工添加参考文献相比,有如下标注:专业规范:这是word专门提供的添加文献的方法;便于维护:无需...

    2024-04-01 00:39:25
  • BitTorrent 性能卓越的原因

    BitTorrent 性能卓越的原因(原文是Incentives Build Robustness in BitTorrent,不知道怎么翻译比较好?)Bram Cohenbram@bitconjurer.org2003年5月22日翻译:小马哥日期:2004-6-1概要BitTorrent 文件发布系统采用针锋相对(tit_for_tat)的方法来达到帕累托有效,与当前已知的协作技术相比,它具有更

    2024-04-01 00:39:01
  • keras安装在虚拟环境并解决vscode中使用时ModuleNotFoundError: No module named ‘tensorflow‘的问题

    keras安装在虚拟环境并解决vscode中使用时ModuleNotFoundError: No module named ‘tensorflow‘的问题

    然后我这时在vscode终端里输入pip list,出来的包还是base环境里面的包, 但是我自己在anaconda prompt中重新创建了这个env后,activate后使用pip list发现其...

    2024-04-01 00:38:56
  • Latex中的表格(1)

    Latex中的表格(1)

    Latex中的表格Latex中的表格相关说明1.1 **一个较为复杂的例子**:1.2 相关说明1.3 命令解释 Latex中的表格相关说明 1.1 一个较为复杂的例子: 具体代码: \begin{t...

    2024-04-01 00:38:51
  • ea 数据库生成java代码_Enterprise Architect Java代码生成文件导入

    我认为你应该避开代码生成模板.这里的问题是集合类的处理超出了正常的代码生成.如果某个类的成员类型是另一个包中的类,则EA会生成正确的import语句 – 但前提是这些类存在于模型中,而collecio...

    2024-04-01 00:38:25
  • JVM 性能调优

    JVM 性能调优

    在高性能硬件上部署程序,目前主要有两种方式:通过 64 位 JDK 来使用大内存; 使用若干个 32 位虚拟机建立逻辑集群来利用硬件资源。使用 64 位 JDK 管理大内存堆内存变大后,虽然垃圾收集的频率减少了,但每次垃圾回收的时间变长。 如果堆内存为14 G,那么每次 Full GC 将长达数十秒。如果 Full GC 频繁发生,那么对于一个网站来说是无法忍受的。对于用户交互性强...

    2024-04-01 00:38:17