經常會在一些專案中用到地址選擇的東西,特別是在一些線上商城要填寫收貨地址的時候,省市區3個聯動的下拉選單是最常用的。然後我也突然有一天在一個小專案中要有收貨地址時,突然發現好像沒有一個現成的庫(要能直接npm install xxx
)去使用?,然後在github去搜了一圈,確實發現有json格式的原始資料,但是結構是同一級的,很難區分是省還是市或者區,雖然作者提供了jquery的外掛,但是畢竟是在手機端使用,最好還是能直接通過js去操作(這樣在nodejs服務端也能使用)。所以決定把原始資料進行重新格式化,轉成省市區巢狀的格式,這樣的話就很容易通過省的ID去拿到市的列表,然後通過市的ID又能拿到區的列表,這正是我們的聯動下拉選單想要的結構。
結構設定
最終要想的結構如下:
{
"320000": {
"code": "320000",
"name": "江蘇省",
"cities": {
"320100": {
"code": "320100",
"name": "南京市",
"districts": {
"320102": "玄武區",
"320104": "秦淮區",
//...
}
}
//...
}
}
//...
}
複製程式碼
我們通過code的前2位來確定省,中間2位來確定市,最後2位來確定區,所以如果是前兩位一樣的就說明是屬於同一個省的,中間2個一樣的就說明是同一個市的,以此類推,需要注意的是上海北京這樣的直轄市,省跟市都是上海,市的code為00,而且只有一個市,下面的區的中間2位code均為01,這裡在轉資料的時候需要注意。
使用 china-location 庫
基於上面的邏輯,寫了個簡單的轉換的js,並提供簡單的API來直接給外面呼叫?。 首先安裝庫china-location:
npm install china-location --save
複製程式碼
或者
yarn add china-location
複製程式碼
然後在JS裡面
//跟庫一起繫結轉換好的資料
import list from 'china-location/dist/location.json'
//in node.js
//const list = require('china-location/dist/location.json');
//ES6 import
import ChinaLocation from 'china-location';
//提供獲取地址,修改地址API的類
//in node.js
//const ChinaLocation = require('china-location');
//初始化例項,並傳入json資料
const location = new ChinaLocation(list);
//獲取初始時當前地址包括code及中文名
//{
// province: {code: '110000', name: '北京市'},
// city: {code: '110000', name: '北京市'},
// district: {code: '110101', name: '東城區'}
//}
const defaultLocation = location.getCurrentAddress();
//修改地址
const newProvince = '320000';
const newCity = '320500';
const newDistrict = '320509';
//一般使用聯動下拉框,獲取選中的code來更新地址,獲得下一級的資料
location.changeProvince(newProvince);
location.changeCity(newCity);
location.changeDistrict(newDistrict);
//也可以一次性都修改
location.changeLocation(newProvince, newCity, newDistrict);
//{
// province: {code: '320000', name: '江蘇省'},
// city: {code: '320500', name: '蘇州市'},
// district: {code: '320509', name: '吳江區'}
//}
//獲取更新後的地址資訊
const newLocation = location.getCurrentAddress();
複製程式碼
API很簡單,初始化,然後修改當前地址,最後獲取當前地址。有了這樣的庫,我們就可以很方便的在瀏覽器頁面,或者在node.js端很容易的去做跟地址相關的邏輯?。
使用自己build出來的地址資料
china-location
打包進的資料可能不是最新的,但是原始資料可能已經更新過,為了能不重複釋出版本,也能使用最新的資料,china-location
也提供了簡單的npm script來轉換本地自定義的原始資料,然後再new ChinaLocation(latestData)
初始化的時候傳入自己手動轉換的json資料。
首先clone原始資料repo:mumuy/data_location, 或者直接把裡面的list.json
儲存下來,然後git clone china-location:
git clone git@github.com:JasonBoy/china-location.git
cd china-location
複製程式碼
進入chian-location根目錄後使用reformat
script來轉換:
npm run reformat -- /path/to/data_location/list.json
複製程式碼
--
後面跟的引數就是原始資料的本地路徑,成功以後會輸出到dist
目錄,裡面的location.json
和location.min.json
, 然後直接拷到你的專案中import,傳到new ChinaLocation(data)
建構函式即可使用最新的資料了。
一個簡單的React元件
以上是純JS的使用,當然如果我們的開發用一些UI庫的話,比如React, 我也寫了個簡單的React元件react-china-location, 樣式都是html原生的下拉框樣式,這裡只做一個demo使用,你可以根據這個邏輯做出符合專案UI要求的元件:
在react-china-location
裡面的china-location
是放在peerDependences
中的,所以china-location
也需要單獨安裝:
npm install china-location react-china-location --save
複製程式碼
然後在你的JSX中:
import locationData from 'china-location/dist/location.json';
import ChinaLocation from 'react-china-location';
class App extends React.Component {
constructor (props) {
super(props);
this.onLocationChange = this.onLocationChange.bind(this);
this.state = {
currentLocation: {},
}
}
onLocationChange (newLocation) {
//{
// province: {code: '110000', name: '北京市'},
// city: {code: '110000', name: '北京市'},
// district: {code: '110101', name: '東城區'}
//}
console.log(newLocation);
//更新到state
this.setState({
currentLocation: newLocation,
});
}
render () {
<div>
<ChinaLocation list={locationData} onLocationChange={this.onLocationChange}/>
</div>
}
}
複製程式碼
<ChinaLocation>
元件裡的list
prop就是轉換後的json資料, 而onLocationChange
回撥是當使用者選擇不同的省市區時的回撥,會傳入最新的location資料,然後就可以setState更新到頁面的其他UI上。
結論
希望這個簡單的china-location庫能給其他的小夥伴在專案中使用到地址邏輯的時候帶來方便,做到開箱即用,而無需浪費時間自己手動再寫一遍, 把更多的時間專注在自己業務邏輯上。