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

本文转自:http://blog.csdn.net/eadio/article/details/52913363

前瞻

目前学习小程序更多的是看看能否二次封装其它组件,利于以后能快速开发各种小程序应用。目前发现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的规范的】

<?php  
header("Content-type: text/html; charset=utf-8");   
  
$type=$_REQUEST["type"];//获取省市区的标志  
$fcode=$_GET["fcode"];  
  
$retArr=[  
    "status"=>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.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方法::

/**  
 * 网络发送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::

<import src="../../template/cityTemplate.wxml"/>  
<template is="city" data="{{...city}}" />  

demo.js::

var city = require( '../../common/cityTemplate' );  
Page( {  
  data: {  
  
  },  
  onLoad: function( options ) {  
    var _that = this;  
    //创建三级联动数据对象 ---- 这个city对象是固定的,只有请求的url是根据各自的服务端地址来更改的  
    _that.setData( {  
      city: {  
        province: {},//格式province:{code: ["11000", "12000"], name: ["北京市", "上海市"]},只能固定是name和code,因为模板需要根据这俩参数显示  
        city: {},  
        county: {},  
        provinceIndex: 0,  
        cityIndex: 0,  
        countyIndex: 0,  
        cityUrl: "http://localhost:8282/phpserver/areas.php?type=city&fcode=",//type表示获取地区 fcode是一级code码,到时具体根据后端请求参数修改  
        countyUrl: "http://localhost:8282/phpserver/areas.php?type=county&fcode="  
      }  
    })  
    var _url = "http://localhost:8282/phpserver/areas.php";  
    var _data = { 'type': 'province', 'fcode': '0' };  
    city.initCityFun( _that, _url, _data );  
  }  
})  

以上完整代码文件,最终测试如下:


这里存在一个bug,开启下拉刷新和picker组件的下拉会重叠了,不知道是开发工具原因,还是还为修改的bug。。。只能等微信方面更新消息给反馈了


今天更新的0.10.102700这个版本后,发现使用text组件触发不了picker组件了,经过一番测试后需把picker组件内的text标签换成view标签才能正常执行业务。

以上实例的cityTemplate.wxml文件里面text标签请自行更换成view标签。在进行测试~


昨天发现一个bug,请重新复制cityTemplate.js文件,这里纠正的是:触发一级下拉事件的时候先清空二级三级的内容和充值默认索引值为0,触发二级下拉事件的时候清空三级的内容和默认索引值。保证每次点击选择都会重新触发事件获取值。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容