微信小程序学习:使用picker封装省市区三级联动模板

     目前学习小程序更多的是看看能否二次封装其它组件,利于以后能快速开发各种小程序应用。目前发现picker的selector模式只有一级下拉,那么我们是否可以通过3个picker来实现三级联动模板的形式来引入其它页面中呢?答案是肯定可以的。那么我的思路是这样的:


1、使用template模板语法进行封装,数据从页面传入

2、根据picker组件的语法,range只能是一组中文地区数组,但是我们需要每个地区的唯一码来触发下一级联动数据。这样,我的做法是通过一个对象里面的两组数据分表存储中文名和唯一码的两个对象数组。格式【province:{code:['110000', '220000'...], name: ['北京市', '天津市'...]}】,这个格式是固定的,需要服务端配合返回

3、通过picker的bindchange事件来获取下一级的数据,每个方法都写入函数中在暴露出来供页面调用


然后讲下我demo的目录结构:

common

    -net.js//wx.request请求接口二次整合

    -cityTemplate.js//三级联动方法

page

    -demo

        -demo.js

        -demo.wxml

template

    -cityTemplate.wxml

app.js

app.json

app.wxss


然后,使用phpstudy搭建了简单的服务端供测试。不要问我服务端的为啥是这样的,我也不懂,刚入门我只要数据...

当然你可以省掉这一步,将数据直接固定在demo.js里面进行测试...

代码如下:【服务端的返回数据格式是遵循了下面的retArr的规范的】

true,
	"data"=>[],
	"msg"=>""
];

if($type!="province" && $type!="city" && $type!="county"){
	$retArr["status"]=false;
	$retArr["msg"]="获取地区类型错误,请检查";
	
	echo json_encode($retArr);
	exit;
}

function getProvince(){
	$province=[];
	$code=["110000", "350000", "710000"];
	$province["code"]=$code;
	$name=["北京市", "福建省", "台湾省"];
	$province["name"]=$name;
	$fcode=["0", "0", "0"];
	$province["fcode"]=$fcode;
	return $province;
}
function getCity($P_fcode){
	$city=[];
	$code=[];
	$name=[];
	$fcode=[];
	if($P_fcode=="110000"){
		$code=["110100"];
		$name=["北京市"];
		$fcode=$P_fcode;
	}
	if($P_fcode=="350000"){
		$code=["350100", "350200", "350300", "350400", "350500", "350600", "350700", "350800", "350900"];
		$name=["福州市", "厦门市", "莆田市", "三明市", "泉州市", "漳州市", "南平市", "龙岩市", "宁德市"];
		$fcode=$P_fcode;
	}
	if($P_fcode=="710000"){
		
	}
	$city=["code"=>$code, "name"=>$name, "fcode"=>$fcode];
	return $city;
}
function getCounty($P_fcode){
	$county=[];
	$code=[];
	$name=[];
	$fcode=[];	
	if($P_fcode=="110100"){
		$code=["110101", "110102", "110103", "110104", "110105", "110106", "110107"];
		$name=["东城区", "西城区", "崇文区", "宣武区", "朝阳区", "丰台区", "石景山区"];
		$fcode=$P_fcode;
	}
	if($P_fcode=="350100"){
		$code=["350102", "350103", "350104"];
		$name=["鼓楼区", "台江区", "苍山区"];
		$fcode=$P_fcode;
	}
	if($P_fcode=="350200"){
		$code=["350203", "350205", "350206"];
		$name=["思明区", "海沧区", "湖里区"];
		$fcode=$P_fcode;
	}
	$county=["code"=>$code, "name"=>$name, "fcode"=>$fcode];
	return $county;
}

//var_dump($province);
if($type=="province"){
	$province=getProvince();
	$retArr["data"]=$province;	
}else if($type=="city"){
	$city=getCity($fcode);
	$retArr["data"]=$city;
}else if($type="county"){
	$county=getCounty($fcode);
	$retArr["data"]=$county;
}

echo json_encode($retArr);


?>


接下来是cityTemplate.wxml::


cityTemplate.js::

/**
 * 获取三级联动的三个函数
 * that:   注册页面的this实例 必填
 * p_url:  一级省份url 必填
 * p_data:一级省份参数 选填
 */
var net = require( "net" );//引入request方法
var g_url, g_datd, g_cbSuccess, g_cbSuccessErr, g_cbFail, g_cbComplete, g_header, g_method;


function initCityFun( that, p_url, p_data ) {
    //获取一级省份数据
    console.log(p_url+JSON.stringify(p_data));
    g_cbSuccess = function( res ) {
      that.setData( {
        'city.province': res
      });
    };
    net.r( p_url, p_data, g_cbSuccess, g_cbSuccessErr, g_cbFail, g_cbComplete, g_header, g_method );


    //点击一级picker触发事件并获取市区方法
    var changeProvince = function( e ) {
        that.setData( {
            'city.city': {},
            'city.county': {},
            'city.provinceIndex': e.detail.value,
            'city.cityIndex': 0,
            'city.countyIndex': 0
        });
        var _fcode = that.data.city.province.code[ e.detail.value ];
        if( !_fcode ) {
            _fcode = 0;
        }
        var _cityUrl = e.target.dataset.cityUrl;


        g_url = _cityUrl + _fcode;


        console.log("province:"+g_url);


        g_cbSuccess = function( res ) {
            console.log(res);
            that.setData( {
                'city.city': res
            });
        }
        net.r( g_url, g_datd, g_cbSuccess, g_cbSuccessErr, g_cbFail, g_cbComplete, g_header, g_method );
    };
    that[ "provincePickerChange" ] = changeProvince;


    //点击二级picker触发事件并获取地区方法
    var changeCity = function( e ) {
        that.setData( {
            'city.county': {},
            'city.cityIndex': e.detail.value,
            'city.countyIndex': 0
        });
        var _fcode = that.data.city.city.code[ e.detail.value ];
        if( !_fcode ) {
            _fcode = 0;
        }
        var _countyUrl = e.target.dataset.countyUrl;
        g_url = _countyUrl + _fcode;


        g_cbSuccess = function( res ) {
            that.setData( {
                'city.county': res
            });
        };
        net.r( g_url, g_datd, g_cbSuccess, g_cbSuccessErr, g_cbFail, g_cbComplete, g_header, g_method );
    };
    that[ "cityPickerChange" ] = changeCity;


    //点击三级picker触发事件
    var changeCounty = function( e ) {
        that.setData( {
            'city.countyIndex': e.detail.value
        });
    };
    that["countyPickerChange"]=changeCounty;
}


function getProvinceFun(that, p_url, p_data){
    g_cbSuccess = function( res ) {
      that.setData( {
        'city.province': res
      });
    };
    net.r( p_url, p_data, g_cbSuccess, g_cbSuccessErr, g_cbFail, g_cbComplete, g_header, g_method );
}


module.exports={
    initCityFun: initCityFun,
    getProvinceFun: getProvinceFun
}

顺道net.js方法::

注意::后端返回数据需严格按照如下格式,否则报未按照接口约定返回:

{
status: true/false,//true=业务处理成功,false=业务处理失败
data: []/{}/"",//业务处理成功反馈的数据
msg: ""//业务处理错误反馈的消息
}

/**
 * 网络发送http请求,默认为返回类型为json
 * 
 * url: 必须,其他参数非必须  接口地址
 * data:请求的参数 Object或String
 * successFun(dts):成功返回的回调函数,已自动过滤微信端添加数据,按接口约定,返回成功后的data数据,过滤掉msg和status
 * successErrorFun(msg):成功执行请求,但是服务端认为业务错误,执行其他行为,默认弹出系统提示信息.
 * failFun:接口调用失败的回调函数
 * completeFun:接口调用结束的回调函数(调用成功、失败都会执行)
 * header:object,设置请求的 header , header 中不能设置 Referer
 * method:默认为 GET,有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
 * 
 */
function r( url, data, successFun, successErrorFun, failFun, completeFun, header, method ) {
    var reqObj = {};
    reqObj.url = url;
    reqObj.data = data;

    //默认头为json
    reqObj.header = { 'Content-Type': 'application/json' };
    if( header ) {
        //覆盖header
        reqObj.header = header;
    }


    if( method ) {
        reqObj.method = method;
    }
    reqObj.success = function( res ) {
        var returnData = res.data; //将微信端结果过滤,获取服务端返回的原样数据
        var status = returnData.status; //按接口约定,返回status时,才调用成功函数
        //console.log(res);
        //正常执行的业务函数
        if( status == true ) {
            if( successFun ) {
                var dts = returnData.data;
                successFun( dts );//回调,相当于获取到data后直接在回调里面处理赋值数据
            }
        } else if( status == false ) {
            var msg = returnData.msg;
            if( !successErrorFun ) {
                console.log( msg );
            } else {
                successErrorFun( msg );
            }

        } else {
            console.log( "服务端没有按照接口约定格式返回数据" );
        }


    }
    reqObj.fail = function( res ) {
        if( failFun ) {
            failFun( res );
        }
    }
    reqObj.complete = function( res ) {
        if( completeFun ) {
            completeFun( res );
        }
    }


    wx.request( reqObj );
}

module.exports = {
    r: r
}


核心代码就是上面这三个文件,接下来是demo文件做测试::

demo.wxml::