置顶 Taro教程之开发一款相亲类微信小程序-省市区选择页
发布于 1 个月前 作者 JavaBird 153 次浏览 最后一次编辑是 23 天前 来自 分享

今天我们接着开发省市县区域选择组件,废话不多说,开始撸代码。

省市县区域选择组件开发

在上一个教程我们让用户选择了性别,接下来我们让用户选择工作单位区域。 因为省、市、县区域选择器在移动端App和WebApp的开发过程中是很普遍的,为了便于复用,我们开发成组件的形式,方便有需要的页面进行调用。 我们先看一下开发完成的效果图: QQ20190113-200513.png

这里Taro提供了现成的组件来帮助我们实现,这个组件就是PickerView,它是一个嵌入页面的滚动选择器,当然picker选择器本身就提供省、市、区选择器,但是它必须通过手动触发才会从底部弹出来,和我们要求的效果不符合,放弃。

这里我们选择借鉴 vant-weapp 里面的 Area 组件进行改造开发。 我们先看一下这个Area组件是否符合我们的要求?

老夫撸代码

从上图中,我们看到这个组件没法直接拿过来用,但是我们可以使用它的数据和提取数据的方式。

省市区数据字典

从Area中我们可以很容易的获取到所需要的数据:Area.js 为了便于后期数据的管理,我们将数据存放到服务器端,通过小程序发送request请求获得。 在服务器端项目,新建 MiaiApi\data\data.php 文件,然后定义一个常量,代码截图:

QQ20190113-201135.png

将上述数据作为数据字典的数据发送到小程序端。 新建 MiaiApi/src/app/Api/Dictionary.php , 代码如下:

<?php
namespace App\Api;

require dirname(dirname(dirname(__DIR__))).'/data/data.php';

use PhalApi\Api;

/**
 * 数据字典api
 *
 * @author: pythonsir <baidu211@vip.qq.com>
 * @weixin: cxyzxh1388
 */

class Dictionary extends Api{


    /**
     * 获取省市县
     */
    public function getArea(){

        return array('area'=>arealist);

    }


}

现在服务器端代码已经完成

省市区组件开发

新建 Miai/src/components/area/area.js ,代码如下:

import Taro, { Component } from "@tarojs/taro";
import api from "../../config/api";
import { View, PickerView, PickerViewColumn } from "@tarojs/components";
import "./area.less";


export default class Area extends Component {
  state = {
    area: [],
    province_: [],
    city_: [],
    county_: [],
    pindex:0,
    cindex:0,
    coindex:0,
    select_province:'选择省',
    select_city:'选择市',
    select_county:'选择县区'
  };

  componentWillMount() {
    // Taro.showLoading({
    //   title: "数据加载中..."
    // });
  }

  componentDidMount() {

    let that = this;

    Taro.request({
      url: api.getArea,
      method: "POST",
      header: {
        "content-type": "application/x-www-form-urlencoded" // 默认值
      }
    }).then(res => {

        const area = res.data.data.area

        this.setState({
          area:area
        })

        this.setProvince(null,area).then(res => {
          const code = res.code
          this.setCity(code,area).then(res => {

            const city_code = res[this.state.cindex].code
            this.setCounty(city_code,area).catch(err => {
              console.log(err)
            })

          }).catch(err => {
            console.log(err)
          })

        }).catch(err => {
          console.log(err)
        })



    }).catch(err => {
      console.log(err)
    })




  }

  componentWillUnmout() {}

  componentWillReceiveProps() {}


  setProvince = (code,data)=>{

    return new Promise((resolve,reject) => {

      const result = this.getList('province', code, data)

      if(result.length <=0){
        reject(false)
      }

      this.setState({
        province_: result
      })

      resolve(result[this.state.pindex])

    })

  }

  setCity = (code, data) => {

     return new Promise((resolve,reject) => {

       const result = this.getList("city", code.slice(0, 2), data);

       if (result.length <= 0) {
         reject(false)
       }

       this.setState({
         city_:result
       })

       resolve(result)


     })


    }

  setCounty = (code, data) => {

    return new Promise((resolve, reject) => {

      const result = this.getList("county", code.slice(0, 4), data);

      if (result.length <= 0) {
        reject(false)
      }

      this.setState({
        county_: result
      })

      resolve(result);


    })

  }

  getConfig = (type,area) => {

      return (area && area[`${type}_list`]) || {};
  };

  getList=(type,code,area) => {

      let result = [];
      if (type !== 'province' && !code) {
          return result;
      }

      const list = this.getConfig(type,area);

      result = Object.keys(list).map(code => ({
          code,
          name: list[code]
      }));

      if (code) {
          // oversea code
          if (code[0] === '9' && type === 'city') {
              code = '9';
          }

          result = result.filter(item => item.code.indexOf(code) === 0);
      }

      return result;

  }

  onChange = e => {
    const val = e.detail.value
    const area = this.state.area
    if(this.state.pindex != val[0]){
        const pr = this.state.province_[val[0]]
        this.setState({
          pindex:val[0],
          select_province:this.state.province_[val[0]].name,
        })
        this.setCity(pr['code'].slice(0, 2),area).then(res => {
          if(res.length == 1){
            this.setState({
              select_city:res[this.state.cindex].name
            })
          }else{
            this.setState({
              select_city:'请选择市'
            })
          }
          const city_code = res[this.state.cindex].code
          this.setCounty(city_code, area).then(res => {
            if(res.length == 1){
              this.setState({
                select_county:res[this.state.coindex].name
              })
            }else{
              this.setState({
                select_county:'请选择区县'
              })
            }
          }) .catch(err => {
            console.log(err)
          })
        }).catch(err => {
          console.log(err)
        })

    }

    if(this.state.cindex != val[1]){

      const cr = this.state.city_[val[1]];

      this.setState({
        cindex:val[1],
        select_city:this.state.city_[val[1]].name,
        select_county:'请选择区县'
      })

      this.setCounty(cr["code"].slice(0, 4), area).catch(err => {
        console.log(err);
      });

    }

    if(this.state.coindex != val[2]){
      this.setState({
        coindex:val[2],
        select_county:this.state.county_[val[2]].name
      })
    }

    this.props.onChange({
      province: this.state.select_province == '选择省' ?'': this.state.select_province,
      city: this.state.select_city == '请选择市'?'':this.state.select_city,
      county: this.state.select_county == '选择县区'?'':this.state.select_county
    })

  };


  render() {
    return (
      <View className="content">
        <View className="select">
          <View className="province">{this.state.select_province}</View>
          <View className="city">{this.state.select_city}</View>
          <View className="county">{this.state.select_county}</View>
        </View>
        <PickerView
          indicatorStyle="height: 50px;"
          style="width: 100%;height:200px;"
          onChange={this.onChange}
        >
          <PickerViewColumn className="pvc">
            {this.state.province_.map(item => {
              return <View>{item["name"]}</View>;
            })}
          </PickerViewColumn>
          <PickerViewColumn className="pvc">
            {this.state.city_.map(item => {
              return <View>{item["name"]}</View>;
            })}
          </PickerViewColumn>
          <PickerViewColumn className="pvc">
              {this.state.county_.map(item => {
                return <View>{item["name"]}</View>;
              })}
            </PickerViewColumn>
        </PickerView>
      </View>
    );
  }
}

新建 Miai/src/components/area/area.less ,样式代码如下:

.content {
  position: relative;
  margin-top: 20px;
  margin-left: 15px;
  margin-right: 15px;
  margin-bottom: 20px;
  box-sizing: border-box;
  background-color: #ffffff;
  height: 100%;
}
.pvc {
    font-size: 28px;
    view{
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
}
.select{
  position: absolute;
  left: 0px;
  top: 0px;
  z-index: 100;
  background-color: #ffffff;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  width: 100%;
  height: 150px;
  view{
    font-size: 30px;
    font-weight: 600;
  }
}

在area.js的代码中,关键是如何实现省、市、区的联动,关键方法如下:

  1. setProvince 设置省数据

  2. setCity 设置市数据

  3. setCounty 设置区数据

  4. getConfig 通过传入不同的参数获取从服务器端传过来数据字典的值

  5. getList 将数据字典中的值转换为数据的形式,方便PickerView使用

  6. onChange 主要是联动显示省、市、区的数据,并把数据传递给父组件中

搜索微信公众号:老夫撸代码 回复数字 1005 获取完整教程以及代码仓库地址

关注微信公众号:老夫撸代码

老夫撸代码


版权声明:未经授权,不得转载

回到顶部