适应移动端的地址四级(省市区街道)联动选择
首先推荐两款个人比较优秀的控件:
一、https://huangchanghuan.github.io/city-picker/
这个是由 city-picker 控件(npm 安装方法: npm install city-picker),地址三级改造而来,数据由京东数据库提供。
优点:
1. 样式比较容易自定义;
2. 对省级地址按字母进行了区分,直观了然。
缺点:
1. 储存地址数据的文件,省市区街道四级在一个文件里,该文件接近 1M ,比较耗费流量;
2. 数据是由京东数据库提供,如果京东的地址数据库有更改,还需要手动进行更新。
二、http://jquerywidget.com/jquery-citys/
该地址数据库来源 http://passer-by.com/data_location/list.json ,由统计局最新数据同步。
优点:
1. 地址数据更新容易,能获取到统计局的最新数据;
2. 街道地址异步调用,根据不同的三级(区县)分为了多个 json 文件,文件较小。
缺点:
1. 默认样式比较适合电脑端,移动端需要更改 select 和 option 标签为其他标签(如:ul li),样式难以调整;
2. 需要更改源 js 文件比较多。
最近开发的项目中就是使用的第二个控件,来做的调整,项目运行在微信公众号中。下面详细介绍下步骤和源码分析
源码下载和介绍地址:https://github.com/xinjie-just/address-select.git
效果图在 iPhone6 模拟机下演示:
图1. 初始化页面,未打开地址选择器时:
图2:地址选择器打开,待选择省级时:
图三:街道地址加载中:
图四:回显
源码分析:
<label for="Addr" id="areaLabel" class="address"> <span>所在地区</span> <input type="text" name="Addr" id="Addr" readonly placeholder="请选择地区"> </label> <div id="addressSelectWrapper"> <div id="addressSelect"> <div class="tip"> <h3>所在地区</h3> <button type="button" id="cancel"></button> </div> <div id="address"> <ul class="selected-address"> <li class="lastarea" id="lastprovince">请选择</li> <li class="lastarea" id="lastcity">请选择</li> <li class="lastarea" id="lastarea">请选择</li> <li class="lastarea" id="lasttown">请选择</li> </ul> <div class="address-content"> <ul id="province"></ul> <ul id="city"></ul> <ul id="area"></ul> <ul id="town"></ul> </div> </div> </div> </div>
1. label#areaLabel 是用来显示地址和打开地址选择器的标签。
2. div#addressSelectWrapper 是用来存放整个地址选择器的容器。
3. div#addressSelect 是用来选择地址的容器,占 div#addressSelectWrapper 高度比例 70%。
4. div.tip 作为标题提示,包含有关闭按钮。
5. ul.selected-address 作为待选择地址提示和回显地址的列表
6. div.address-content 全部地址以及异步调用的街道地址的显示容器。
根据后期的优化和踩过的坑,对 js 源码部分解释:
一、在数据处理的市级数据处理时,如果按照以下选择会出现 bug
1. 选择直辖市 -> 2. 重新选择非直辖市的省级 -> 3. 选择任意一个城市
这种情况下,选择任意一个城市,它下面的区县级地址都是第一个城市的区县地址。
例如:
1. 选择北京市 -> 2. 重新选择四川省 -> 3. 选择四川省下的任意一个城市
它下面的区县都是第一个城市"成都"的区县
自贡市下面本该有自流井区、贡井区等,结果出现了成都市(排在第一位置的城市)的锦江区,青羊区等。
出现这个 bug 原因是选择直辖市后,在选择其它非直辖市的省级,没有重置 hasCity 的值,使其变为非直辖市。 hasCity = true
//市级数据处理 city: function () { try { toolHanlder.showContent(2); toolHanlder.showLoading(); toolHanlder.createHtml(2); //由于存在直辖市的问题,所以这里需要对市区进行特殊处理 var len = $city.find("li").length; if (!len) { hasCity = false; $lastCity.hide(); $city.hide(); dataHanlder.area(); } else { hasCity = true; // 重置,使它表示非直辖市。否者如果先点击直辖市后,这里的值会是先前点击的直辖市,即 hasCity = false; // 选择城市 $city.find("li") .click(function() { var $this = $(this); toolHanlder.liClick($this, 2); }); } } catch (e) { console.log(e.message); } finally { toolHanlder.hideLoading(); } },
二、显示动画
在选择区县级地址后,将会调用该区县下的街道地址,如果网络慢的原因将会导致加载时间过长,中间有一些停顿的时间用户不知道接下来的操作流程。
//显示加载动画 showLoading: function() { $container.find("div.address-content").append('<div class="loading">加载中</div>'); }, //隐藏加载动画 hideLoading: function() { $container.find("div.loading").remove(); },
在每一级数据处理中,都去调用该方法显示加载动画,待数据加载完成后再隐藏加载动画。
三、为当前待地址特殊标记
给“作为待选择地址提示和回显地址的列表项 li.lastarea ”添加 active 类
//显示地区选择区域 showContent: function(level) { //显示对应的区域选择框 //先移除所有的选择效果 $lastProvince.siblings().addBack().removeClass('active'); // lxj, 上次成功选择的省级区域,去除同级别的li的样式 $province.siblings().addBack().hide(); // lxj, 当前的省级选择,将同级别的影藏 switch (level) { case 1: { $lastProvince.addClass('active').show(); $province.show(); } break; case 2: { $lastCity.addClass('active').show(); $city.show(); } break; case 3: { $lastArea.addClass('active').show(); $area.show(); } break; case 4: { $lastTown.addClass('active').show(); $town.show(); } break; } },
如“显示地址选择区域”中,在每一级待要选择的地址中添加 active 类 $lastCity.addClass('active')
更多说明及解释,查看 https://github.com/xinjie-just/address-select.git README.md。