移动端省市区级联选择器

所属分类:输入-选择框

 74565  368  查看评论 (28)
分享到微信朋友圈
X
移动端省市区级联选择器 ie兼容10

更新时间:2018/2/6 下午12:24:48

更新说明:修复无区地级市的选择问题


前言

最近在做移动端项目的时候遇到了省市区选择的功能。以往做项目时都是省市区分开的下拉框样式。这次希望实现效果图要求的级联选择器。我是 Framework7 框架的忠实粉丝,庆幸的是 Framework7 已经有模拟 iOS 选择框效果的 Picker 组件。在开发之前我先搜索了现有的一些选择器插件,整体而言都能满足需求但都不完美,比如滑动不流畅、显示有 Bug 等等。

Picker 级联选择器

基于 Framework7 制作级联选择器比较简单,关键是生成省市区数组以及省市区之间的联动。

以下是 CityPicker 的基本参数设置:

var pickerLocation = myApp.picker({
    input: '#location',//选择器
    rotateEffect: true,//设置旋转效果
    toolbarTemplate: '',//自定义按钮
    cols: [{
            cssClass: 'f-s-14',//添加自定义类
            width: 100,//列宽
            textAlign: 'left',//对齐方式
            values: province,//省数组
            onChange: function(picker, province) {//联动方法

            }
        },
        {
            cssClass: 'f-s-14',//添加自定义类
            width: 100,//列宽
            textAlign: 'center',//对齐方式
            values: city,//市数组
            onChange: function(picker, city) {//联动方法

            }
        },
        {
            cssClass: 'f-s-14',//添加自定义类
            width: 100,//列宽
            textAlign: 'right',//对齐方式
            values: area,//区数组
        }
    ]
});

其中省市区的格式都是基本数组,所以必须循环省市区数据生成相应的数组或者数据本身具有可以直接获取数组的结构。

province = ['北京','天津','河北','山东',...]
city = ['济南','青岛','淄博','滨州',...]
area = ['滨城区','惠民县','阳信县','博兴县',...]

省市区数据结构

没有想到一个简单的问题,最后竟然扯到了数据结构。经过尝试和思考,最终出现了三种数据结构,而这些东西应该都不是新鲜事。鉴于学识有限,我只能浅尝辄止的对比三者的异同,以及给出自己循环数据的方法。

1.无子父级关系的数组

去年做项目时省市区数据并没有从接口读取,而是保存到一个 JS 文件中。以下是后台从数据库导出的原始省市区数据片段(2016 年的数据,应该比较全,我删除了香港、澳门及台湾)。

[
    {
      "region_id": 11,
      "region_name": "北京市",
      "region_sort": 1,
      "region_remark": "直辖市",
      "pinyin": "beijingshi",
      "py": "bjs",
      "area_code": "110000",
      "parent_id": 1,
      "level": 1
    },
    {
      "region_id": 12,
      "region_name": "天津市",
      "region_sort": 2,
      "region_remark": "直辖市",
      "pinyin": "tianjinshi",
      "py": "tjs",
      "area_code": "120000",
      "parent_id": 1,
      "level": 1
    },
    {
      "region_id": 13,
      "region_name": "河北省",
      "region_sort": 3,
      "region_remark": "省份",
      "pinyin": "hebeisheng",
      "py": "hbs",
      "area_code": "130000",
      "parent_id": 1,
      "level": 1
    },
    ...
    {
      "region_id": 101,
      "region_name": "北京市",
      "region_sort": 1,
      "region_remark": null,
      "pinyin": "beijingshi",
      "py": "bjs",
      "area_code": "110100",
      "parent_id": 11,
      "level": 2
    },
    {
      "region_id": 102,
      "region_name": "天津市",
      "region_sort": 2,
      "region_remark": null,
      "pinyin": "tianjinshi",
      "py": "tjs",
      "area_code": "120100",
      "parent_id": 12,
      "level": 2
    },
    {
      "region_id": 105,
      "region_name": "邯郸市",
      "region_sort": 5,
      "region_remark": null,
      "pinyin": "handanshi",
      "py": "hds",
      "area_code": "130400",
      "parent_id": 13,
      "level": 2
    },
    ...
  }
]

 这个数据并没有明确的子父级关系,只能通过 parent_id 查找对应的省市。循环方式如下:

/**
 * [getProvince 获取省]
 * @param  {[Object]} regions [省市区数据]
 * @return {[Array]}          [省数组]
 */
function getProvince(regions) {

    $.each(regions, function() {
        if (this.level === 1) {
            province.push(this.region_name);
        }
    });

    return province;
}

/**
 * [getCity 获取市]
 * @param  {[Object]} regions      [省市区数据]
 * @param  {[String]} provinceName [省名]
 * @return {[Array]}               [市数组]
 */
function getCity(regions, provinceName) {

    var province_id = 0,
        cityArr = [];

    $.each(regions, function() {
        if (this.level === 1 && this.region_name === provinceName) {
            province_id = this.region_id;
            return false;
        }
    });
    $.each(regions, function() {
        if (this.level === 2 && this.parent_id === province_id) {
            cityArr.push(this.region_name)
        }
    });

    return cityArr;
}

/**
 * [getArea 获取区]
 * @param  {[Object]} regions      [省市区数据]
 * @param  {[String]} provinceName [省名]
 * @param  {[String]} cityName     [市名]
 * @return {[Array]}               [区数组]
 */
function getArea(regions, provinceName, cityName) {

    var province_id = 0,
        city_id = 0,
        areaArr = [];

    $.each(regions, function() {
        if (this.level === 1 && this.region_name === provinceName) {
            province_id = this.region_id;
        }
        if (this.level === 2 && this.region_name === cityName && this.parent_id === province_id) {
            city_id = this.region_id;
            return false;
        }
    });
    $.each(regions, function() {
        if (this.level === 3 && this.parent_id === city_id) {
            areaArr.push(this.region_name)
        }
    });

    return areaArr;
}

更多方法请参考

http://www.cnblogs.com/nzbin/p/7754447.html
相关插件-选择框

radio checkbox

利用css3技术,实现替代浏览器自带的radio checkbox功能。不用js技术,纯轻量级的。
  选择框
 31451  312

vue 城市下拉模拟组件Citypicker

基于vue开发的城市模拟下拉组件
  选择框
 43814  385

移动端vue切换城市带自动定位

vue.js定位后 选择其他城市进行切换,适用移动端
  选择框
 26709  308

vue选择检索国家页面模板(原创)

vue.js基于json异步调用可选择并且可以通过国家名称和手机区号进行检索相应的国家,并且有中文、日语、英语、越南语、韩语、五种语言,这些语言的显示是根据游览器语言而定。代码比较容易理解,用起来很方便。(支持多语言自适应手机和网站)
  选择框
 24125  271

讨论这个项目(28)回答他人问题或分享插件使用方法奖励jQ币 评论用户自律公约

    白云间. 0
    2020/9/8 18:24:54
    如果页面过长 会导致无法滑动页面 怎么解决呢 回复
    柳姑娘吖?? 0
    2020/8/9 18:11:43
    怎么取区对应的id 回复
    ?深蓝ヤ 0
    2020/2/29 16:41:45
    怎么设置默认值啊? 回复
    nzb329 0
    2019/5/23 9:18:24
    这个小插件建议搭配 Framework7 使用,最后不要单独使用,不然会有一些奇怪问题 回复
    ?? 0
    2019/5/8 17:17:34
    在移动端里 picker组件高度设置称100%, 但我页面就只显示一层了,改成height:auto 弹出只弹出一点
        ??0
        2019/5/8 17:19:13
        页面只显示一屏, 高度改成auto,组件样式只弹出一部分得在滑动屏幕 才显示全
    回复
    闭眼〆聆聽心碎dé寂寥 0
    2018/12/29 10:08:51
    我发现取消和完成这两个按钮功能是一样的 点击取消没有取消的功能的 回复
    伏特人族 0
    2018/9/3 9:43:10
    我的点击事件没了, 也不报错, 为什么呢, 回复
    樊强 0
    2018/8/8 17:01:13
    怎么取值昵?
        nzb3291
        2018/8/8 22:39:51
        关于取值可以看一下 framework7 picker 组件的方法,使用这个城市级联选择器最好还是与和 framework7 框架搭配
    回复
    葭叮“柳”! 0
    2018/7/24 15:06:48
    会跟一些js起冲突,比如click事件单击失效了 回复
    mae 0
    2018/6/25 12:05:07
    怎么拿到value
        渴望上路0
        2018/7/18 18:18:47
        怎么拿啊 没看懂
    回复
😃
  • 😀
  • 😉
  • 😥
  • 😵
  • 😫
  • 😘
  • 😡
  • 👍
  • 🌹
  • 👏
  • 🍺
  • 🍉
  • 🌙
  • 💖
  • 💔
😃
  • 😀
  • 😉
  • 😥
  • 😵
  • 😫
  • 😘
  • 😡
  • 👍
  • 🌹
  • 👏
  • 🍺
  • 🍉
  • 🌙
  • 💖
  • 💔
取消回复