经常会在一些项目中用到地址选择的东西,特别是在一些在线商城要填写收货地址的时候,省市区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库能给其他的小伙伴在项目中使用到地址逻辑的时候带来方便,做到开箱即用,而无需浪费时间自己手动再写一遍, 把更多的时间专注在自己业务逻辑上。