原生JS实现省市区(县)三级联动选择

wo e le

原文地址→看过来

写在前面

前段时间写一个关于天气的东西,里面的省市区(县)城市选择让我很头疼,在网上搜索出来大都是借助插件或者第三方库,感觉这样做代码会很重,所以索性就把几种城市选择的方式实现一遍,以备日后的不时之需。这三种方法都是针对pc端的,并且都是使用原生js实现的,连jq都没使用,于是代码有点繁琐额(尴尬)。。。。不过还是让我把原理讲完吧。

源代码地址→传送门

预览地址→传送门

方法一:下拉选择框实现省市区(县)三级联动

  1. 用下拉框实现省市区三级联动是很常见的一种方式,也很方便。这里需要先了解下select的相关属性及其对象属性,请参考此文
  2. 先看下最终实现效果图:


    select实现三级联动
  3. 思路介绍:
    • 页面加载时,动态获取省份列表并放到下拉菜单的下拉项中:


      select-省份显示
    /*自动加载省份列表*/
(function showProv() {
    btn.disabled = true;
    var len = provice.length;
    for (var i = 0; i < len; i++) {
        var provOpt = document.createElement('option');
        provOpt.innerText = provice[i]['name'];
        provOpt.value = i;
        prov.appendChild(provOpt);
    }
})();
  • 当点击省份列表中的某一项,此时触发省份下拉框的onchange事件,在onchange事件中根据前面所选的省份来显示对应城市。这里用到一个select的selectedIndex属性,从而获取刚刚点击的是哪个省份(生成省份列表时添加了value属性值):
    select-省份显示
    var val = obj.options[obj.selectedIndex].value;  //这里得到的是所选择省份在所有下拉项中为第几项
  • 当点击城市列表中的某一项时,原理同上(此处不赘述)


    select-省份显示
  • 选择城市时存在两种情况,如何城市选项下不存在县区,则直接将所选省市显示在输入框,否则依照上诉原理显示县区
    <!--方法是判断县区的length是否为0-->
    var countryLen = provice[current.prov]["city"][val].districtAndCounty.length;
        if(countryLen == 0){
            addrShow.value = provice[current.prov].name + '-' + provice[current.prov]["city"][current.city].name;
            return;
        }
  • 最后点击县区后再按确定,则可将所选地点显示在输入框中。
  1. 注意:
    • 在未选中具体县区时,按钮为不可点状态
    • 具体的实现主要根据城市数据来进行更细的处理。
  2. 说明:
    • 这里使用的省市区数据来源于网络,不能保证真实性及完整性,仅供案例使用
    • 此处使用的数据类型为js数组,格式参考如下(完整版):
var provice = [
    {
        name: "北京市",
        city: [
            {
                name: "北京市",
                districtAndCounty: ["东城区", "西城区", "崇文区", "宣武区", "朝阳区", "丰台区", "石景山区", "海淀区", "门头沟区", "房山区", "通州区", "顺义区", "昌平区", "大兴区", "怀柔区", "平谷区", "密云县", "延庆县", "延庆镇"]
            }
        ]
    },
    
    ......
    
    {
        name: "河北省",
        city: [
            {
                name: "石家庄市",
                districtAndCounty: ["长安区", "桥东区", "桥西区", "新华区", "裕华区", "井陉矿区", "辛集市", "藁城市", "晋州市", "新乐市", "鹿泉市", "井陉县", "微水镇", "正定县", "正定镇", "栾城县", "栾城镇", "行唐县", "龙州镇", "灵寿县", "灵寿镇", "高邑县", "高邑镇", "深泽县", "深泽镇", "赞皇县", "赞皇镇", "无极县", "无极镇", "平山县", "平山镇", "元氏县", "槐阳镇", "赵县", "赵州镇"]
            },
            
            .......
            
            {
                name: "邯郸市",
                districtAndCounty: ["丛台区", "邯山区", "复兴区", "峰峰矿区", "武安市", "邯郸县", "南堡乡东小屯村", "临漳县", "临漳镇", "成安县", "成安镇", "大名县", "大名镇", "涉县", "涉城镇", "磁县", "磁州镇", "肥乡县", "肥乡镇", "永年县", "临洺关镇", "邱县", "新马头镇", "鸡泽县", "鸡泽镇", "广平县", "广平镇", "馆陶县", "馆陶镇", "魏县", "魏城镇", "曲周县", "曲周镇"]
            }
        ]
    }
]
    

方法二:按级选中省市县/区

  1. 这种方式比上面的下拉框更好看点,操作也更方便点,不过大概的逻辑有点类似。所用省市区数据跟上面的一致。
  2. 先看看这种方式的效果图:


    按级选中省市县/区
  3. 在页面加载时同样先显示出所有的省份列表(方法类似)


    按级选中省市县/区
  4. 点击具体省份时,将省份列表替换成对应的城市列表,点击具体城市时显示对应县区,实现如下:
addrWrap.onclick = function (e) {     //将点击事件委托给列表的父元素
    var n;
    var e = e || window.event;
    var target = e.target || e.srcElement;
    if (target && target.nodeName == 'LI') {
        /*先判断当前显示区域显示的是省市区的那部分*/
        for (var z = 0; z < 3; z++) {
            if (titleWrap[z].className == 'titleSel')
                n = z;
        }
        /*显示的处理函数*/
        switch (n) {
            case 0:
                showCity2(target.index);   //点击的是省份中列表的某一项,接下来则显示城市列表
                break;
            case 1:
                showCountry2(target.index);  //点击的是城市列表中的某一项,接下来则显示县区列表
                break;
            case 2:
                selectCountry(target.index);  //点击具体的某个县区,则将该县区选择
                break;
            default:
                showProv2();
        }
    }
};
按级选中省市县/区

按级选中省市县/区
  1. 上面点击的每一步中将选中项的索引及值保存在一个对象中,以便最后点击确定按钮将选择的省市区显示在输入框中。
  2. 当选择的城市不存在县区时处理跟第一种方式一致。
  3. 当点击分类时,显示对应的内容,同时将保存的对象的值进行处理:


    点击不同分类
        //将事件委托给父元素,根据点击的分类进行处理(html的设置好li的value值)
        if (target.value == '0') {
            showProv2();  
        } else if (target.value == '1') {
            showCity2(current2.prov);
        } else {
            showCountry2(current2.city);
        }
  1. OK

方法三:按字母顺序选中城市

  1. 直接按字母的顺序选中城市这种方式比前两种更简单粗暴也较为简单,代码量也较少。
  2. 先看看这种方式的效果图:


    按字母顺序选中城市
  3. 页面加载时先显示热门城市


    按字母顺序选中城市
  4. 点击不同字母集,显示对应的城市列表
switch (index) {
            case 0:    //0为热门项
                showHotCity();
                break;
            case 6:    //6为最后一栏,字母集个数为2
                showCitys(index, 2);
                break;
            default:   //其余索引,字母集个数都为4
                showCitys(index, 4);
        }
function showCitys(index, m) {
    //通过传入的参数截取城市数据的一部分为当前要显示的城市列表
    var currentAll = cityAll.slice(4 * index - 3, 4 * index + m - 3);  
    
    .....
    
    //将动态生成的列表项放到显示区域
}
  1. 点击具体某一个城市时,将其显示在输入框中。


    按字母顺序选中城市
  2. 这种方式的城市数据跟前两种不同,来源于网上,不能保证真实性及完整性,仅供案例使用,数据格式如下(完整版):
var cityAll = [
    {
        name: "hot",
        citys: ["北京", "上海", "广州", "深圳", "杭州", "南京", "成都", "重庆", "武汉", "长沙", "昆明"]
    },
    {
        name: "A",
        citys: ["阿坝", "阿拉善", "阿里", "安康", "安庆", "鞍山", "安顺", "安阳", "澳门"]
    },
    
    ......
    
    
    {
        name: "Z",
        citys: ["杂多县", "赞皇县", "枣强县", "枣阳市", "枣庄",.......,资阳"]
}

7.完美~

小结

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

推荐阅读更多精彩内容