中國行政區劃資訊JS庫china-location

jasonboy7發表於2018-05-25

經常會在一些專案中用到地址選擇的東西,特別是在一些線上商城要填寫收貨地址的時候,省市區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根目錄後使用reformatscript來轉換:

npm run reformat -- /path/to/data_location/list.json
複製程式碼

--後面跟的引數就是原始資料的本地路徑,成功以後會輸出到dist目錄,裡面的location.jsonlocation.min.json, 然後直接拷到你的專案中import,傳到new ChinaLocation(data)建構函式即可使用最新的資料了。

一個簡單的React元件

以上是純JS的使用,當然如果我們的開發用一些UI庫的話,比如React, 我也寫了個簡單的React元件react-china-location, 樣式都是html原生的下拉框樣式,這裡只做一個demo使用,你可以根據這個邏輯做出符合專案UI要求的元件:

中國行政區劃資訊JS庫china-location

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庫能給其他的小夥伴在專案中使用到地址邏輯的時候帶來方便,做到開箱即用,而無需浪費時間自己手動再寫一遍, 把更多的時間專注在自己業務邏輯上。

相關文章