首先推薦兩款個人比較優秀的控件:
一、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。