Taro教程之相亲类微信小程序开发实战-05省市区选择页
今天我们接着开发省市县区域选择组件,废话不多说,开始撸代码。
省市县区域选择组件开发
在上一个教程我们让用户选择了性别,接下来我们让用户选择工作单位区域。
因为省、市、县区域选择器在移动端App和WebApp的开发过程中是很普遍的,为了便于复用,我们开发成组件的形式,方便有需要的页面进行调用。
我们先看一下开发完成的效果图:
QQ20190113-200513.png
这里Taro提供了现成的组件来帮助我们实现,这个组件就是PickerView,它是一个嵌入页面的滚动选择器,当然picker选择器本身就提供省、市、区选择器,但是它必须通过手动触发才会从底部弹出来,和我们要求的效果不符合,放弃。
这里我们选择借鉴 vant-weapp 里面的 Area 组件进行改造开发。
我们先看一下这个Area组件是否符合我们的要求?
从上图中,我们看到这个组件没法直接拿过来用,但是我们可以使用它的数据和提取数据的方式。
省市区数据字典
从Area中我们可以很容易的获取到所需要的数据:Area.js
为了便于后期数据的管理,我们将数据存放到服务器端,通过小程序发送request请求获得。
在服务器端项目,新建 MiaiApi\data\data.php 文件,然后定义一个常量,代码截图:
将上述数据作为数据字典的数据发送到小程序端。
新建 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的代码中,关键是如何实现省、市、区的联动,关键方法如下:
-
setProvince 设置省数据
-
setCity 设置市数据
-
setCounty 设置区数据
-
getConfig 通过传入不同的参数获取从服务器端传过来数据字典的值
-
getList 将数据字典中的值转换为数据的形式,方便PickerView使用
-
onChange 主要是联动显示省、市、区的数据,并把数据传递给父组件中
搜索微信公众号:老夫撸代码 回复数字 1005
获取完整教程以及代码仓库地址
关注微信公众号:老夫撸代码
老夫撸代码版权声明:未经授权,不得转载