├── .babelrc ├── .gitignore ├── .npmignore ├── README.md ├── package-lock.json ├── package.json ├── src ├── assets │ ├── demo1.png │ ├── demo2.png │ └── picker-preview.jpeg ├── components-ext │ ├── index.js │ └── picker-address │ │ ├── address.js │ │ ├── index.jsx │ │ └── index.scss ├── components │ ├── index.js │ ├── modal │ │ ├── BaseModal.jsx │ │ └── BaseModal.scss │ ├── picker │ │ ├── README.md │ │ ├── index.jsx │ │ └── index.scss │ ├── popup │ │ ├── index.jsx │ │ └── index.scss │ └── scss │ │ ├── animation.scss │ │ └── index.scss ├── container │ ├── home │ │ ├── index.jsx │ │ └── index.scss │ ├── layout.jsx │ └── picker │ │ ├── index.scss │ │ └── picker-demo.jsx ├── index.html ├── main.js └── scss │ ├── button.scss │ ├── index.scss │ ├── list.scss │ └── reset.scss └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "stage-3", 5 | "react" 6 | ] 7 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | build 4 | lib 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | build 4 | src 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 移动端react选择器,支持拓展二级联动,三级联动 2 | 3 | 4 | ## How to use 5 | 6 | ``` 7 | $ npm install spring-picker -S 8 | 9 | import 'spring-picker/lib/style.css'; 10 | import { Picker, Popup } from 'spring-picker'; 11 | 12 | 16 | 20 | 21 | 22 | ``` 23 | 24 | ## How to run 25 | 26 | ``` 27 | # install dependencies 28 | npm install 29 | 30 | # run server 31 | npm start 32 | 33 | # build for production with minification 34 | npm run build 35 | 36 | ``` 37 | 38 | # preview 39 | Chrome打开开发者工具,切换到手机模拟器预览 40 | [https://springalskey.github.io/picker/index.html#/picker-demo](https://springalskey.github.io/picker/index.html#/picker-demo) 41 | 42 | 43 | # mobile qrcode preview 44 | ![image](https://github.com/springalskey/picker/blob/master/src/assets/picker-preview.jpeg) 45 | 46 | 47 | ### example1 48 | ![image](https://github.com/springalskey/picker/blob/master/src/assets/demo1.png) 49 | 50 | ### example2 51 | ![image](https://github.com/springalskey/picker/blob/master/src/assets/demo2.png) 52 | 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spring-picker", 3 | "version": "16.0.1", 4 | "description": "react picker", 5 | "scripts": { 6 | "start": "cross-env NODE_ENV=dev webpack-dev-server --inline --progress", 7 | "build": "rimraf build && cross-env NODE_ENV=production webpack -p --progress", 8 | "build-js": "babel src/components --out-dir lib --source-maps --extensions .jsx,.js --copy-files", 9 | "build-css": "node-sass src/components/scss/index.scss lib/style.css", 10 | "prepublish": "rimraf lib && npm run build-css && npm run build-js", 11 | "gh-pages": "node_modules/.bin/gh-pages -d build" 12 | }, 13 | "babel": { 14 | "presets": [ 15 | "es2015" 16 | ] 17 | }, 18 | "homepage": "https://github.com/springalskey/picker.git", 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/springalskey/picker.git" 22 | }, 23 | "license": "MIT", 24 | "dependencies": { 25 | "lodash": "^4.17.4", 26 | "react": "^16.0.0", 27 | "react-dom": "^16.0.0", 28 | "react-transition-group": "^2.2.1" 29 | }, 30 | "devDependencies": { 31 | "babel-cli": "^6.26.0", 32 | "babel-core": "^6.26.0", 33 | "babel-loader": "^7.1.2", 34 | "babel-polyfill": "^6.26.0", 35 | "babel-preset-es2015": "^6.24.1", 36 | "babel-preset-react": "^6.24.1", 37 | "babel-preset-stage-3": "^6.24.1", 38 | "copy-webpack-plugin": "^4.2.0", 39 | "cross-env": "^5.1.1", 40 | "css-loader": "^0.28.7", 41 | "extract-text-webpack-plugin": "^3.0.2", 42 | "file-loader": "^1.1.5", 43 | "gh-pages": "^1.0.0", 44 | "html-webpack-plugin": "^2.30.1", 45 | "ip": "^1.1.5", 46 | "node-sass": "^4.5.3", 47 | "postcss-loader": "^2.0.8", 48 | "react-router": "^4.2.0", 49 | "react-router-dom": "^4.2.2", 50 | "rimraf": "^2.6.2", 51 | "sass-loader": "^6.0.6", 52 | "style-loader": "^0.19.0", 53 | "url-loader": "^0.6.2", 54 | "webpack": "^3.8.1", 55 | "webpack-dev-server": "^1.16.5" 56 | }, 57 | "bugs": { 58 | "url": "https://github.com/springalskey/picker/issues" 59 | }, 60 | "main": "lib/index.js", 61 | "style": "lib/style.css", 62 | "author": "springalskey" 63 | } 64 | -------------------------------------------------------------------------------- /src/assets/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springalskey/picker/e6acafcff177a23f49c729f27de867ddd8dc4932/src/assets/demo1.png -------------------------------------------------------------------------------- /src/assets/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springalskey/picker/e6acafcff177a23f49c729f27de867ddd8dc4932/src/assets/demo2.png -------------------------------------------------------------------------------- /src/assets/picker-preview.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springalskey/picker/e6acafcff177a23f49c729f27de867ddd8dc4932/src/assets/picker-preview.jpeg -------------------------------------------------------------------------------- /src/components-ext/index.js: -------------------------------------------------------------------------------- 1 | 2 | export { default as PickerAddress } from './picker-address'; 3 | -------------------------------------------------------------------------------- /src/components-ext/picker-address/address.js: -------------------------------------------------------------------------------- 1 | 2 | export const provins = [ 3 | '北京市','天津市','河北省','山西省','内蒙古','辽宁省','吉林省','黑龙江省', 4 | '上海市','江苏省','浙江省','安徽省','福建省','江西省','山东省','河南省', 5 | '湖北省','湖南省','广东省','广西','海南省','重庆市','四川省','贵州省','云南省', 6 | '西藏','陕西省','甘肃省','青海','宁夏','新疆' 7 | ]; 8 | 9 | export const citys = { 10 | '北京市': ['北京市'], 11 | '天津市': ['天津市'], 12 | '河北省': ['石家庄市','唐山市','秦皇岛市','邯郸市','邢台市','保定市','张家口市','承德市','沧州市','廊坊市','衡水市'], 13 | '山西省':['太原市','大同市','阳泉市','长治市','晋城市','朔州市','晋中市','运城市','忻州市','临汾市','吕梁市'], 14 | '内蒙古':['呼和浩特市','包头市','乌海市','赤峰市','通辽市','鄂尔多斯市','呼伦贝尔市','巴彦淖尔市','乌兰察布市','兴安盟','锡林郭勒盟','阿拉善盟'], 15 | '辽宁省':['沈阳市','大连市','鞍山市','抚顺市','本溪市','丹东市','锦州市','营口市','阜新市','辽阳市','盘锦市','铁岭市','朝阳市','葫芦岛市'], 16 | '吉林省':['长春市','吉林市','四平市','辽源市','通化市','白山市','松原市','白城市','延边朝鲜族自治州'], 17 | '黑龙江省':['哈尔滨市','哈尔滨市','鸡西市','鹤岗市','双鸭山市','大庆市','伊春市','佳木斯市','七台河市','牡丹江市','黑河市','绥化市','大兴安岭地区'], 18 | '上海市':['上海市'], 19 | '江苏省':['南京市','无锡市','徐州市','常州市','苏州市','南通市','连云港市','淮安市','盐城市','扬州市','镇江市','泰州市','宿迁市'], 20 | '浙江省':['杭州市','宁波市','温州市','嘉兴市','湖州市','绍兴市','金华市','衢州市','舟山市','台州市','丽水市'], 21 | '安徽省':['合肥市','芜湖市','蚌埠市','淮南市','马鞍山市','淮北市','铜陵市','安庆市','黄山市','滁州市','阜阳市','宿州市','巢湖市','六安市','亳州市','池州市','宣城市'], 22 | '福建省':['福州市','厦门市','莆田市','三明市','泉州市','漳州市','南平市','龙岩市','宁德市'], 23 | '江西省':['南昌市','景德镇市','萍乡市','九江市','新余市','鹰潭市','赣州市','吉安市','宜春市','抚州市','上饶市'], 24 | '山东省':['济南市','青岛市','淄博市','枣庄市','东营市','烟台市','潍坊市','济宁市','泰安市','威海市','日照市','莱芜市','临沂市','德州市','聊城市','滨州市','菏泽市'], 25 | '河南省':['郑州市','开封市','洛阳市','平顶山市','安阳市','鹤壁市','新乡市','焦作市','濮阳市','许昌市','漯河市','三门峡市','南阳市','商丘市','信阳市','周口市','驻马店市'], 26 | '湖北省':['武汉市','黄石市','十堰市','宜昌市','襄樊市','鄂州市','荆门市','孝感市','荆州市','黄冈市','咸宁市','随州市','恩施土家族苗族自治州','直辖行政单位'], 27 | '湖南省':['长沙市','株洲市','湘潭市','衡阳市','邵阳市','岳阳市','常德市','张家界市','益阳市','郴州市','永州市','怀化市','娄底市','湘西土家族苗族自治州'], 28 | '广东省':['广州市','韶关市','深圳市','珠海市','汕头市','佛山市','江门市','湛江市','茂名市','肇庆市','惠州市','梅州市','汕尾市','河源市','阳江市','清远市','东莞市','中山市','潮州市','揭阳市','云浮市'], 29 | '广西':['南宁市','柳州市','桂林市','梧州市','北海市','防城港市','钦州市','贵港市','玉林市','百色市','贺州市','河池市','来宾市','崇左市'], 30 | '海南省':['海口市','三亚市'], 31 | '重庆市':['市辖区','县'], 32 | '四川省':['成都市','自贡市','攀枝花市','泸州市','德阳市','绵阳市','广元市','遂宁市','内江市','乐山市','南充市','眉山市','宜宾市','广安市','达州市','雅安市','巴中市','资阳市','阿坝藏族羌族自治州','甘孜藏族自治州','凉山彝族自治州'], 33 | '贵州省':['贵阳市','六盘水市','遵义市','安顺市','铜仁地区','黔西南布依族苗族自治州','毕节地区','黔东南苗族侗族自治州','黔南布依族苗族自治州'], 34 | '云南省':['昆明市','曲靖市','玉溪市','保山市','昭通市','丽江市','思茅市','临沧市','楚雄彝族自治州','红河哈尼族彝族自治州','文山壮族苗族自治州','西双版纳傣族自治州','大理白族自治州','德宏傣族景颇族自治州','怒江傈僳族自治州','迪庆藏族自治州'], 35 | '西藏':['拉萨市','昌都地区','山南地区','日喀则地区','那曲地区','阿里地区','林芝地区'], 36 | '陕西省':['西安市','铜川市','宝鸡市','咸阳市','渭南市','延安市','汉中市','榆林市','安康市','商洛市'], 37 | '甘肃省':['兰州市','嘉峪关市','金昌市','白银市','天水市','武威市','张掖市','平凉市','酒泉市','庆阳市','定西市','陇南市','临夏回族自治州','甘南藏族自治州'], 38 | '青海':['西宁市','海东地区','海北藏族自治州','黄南藏族自治州','海南藏族自治州','果洛藏族自治州','玉树藏族自治州','海西蒙古族藏族自治州'], 39 | '宁夏':['银川市','石嘴山市','吴忠市','固原市','中卫市'], 40 | '新疆':['乌鲁木齐市','克拉玛依市','吐鲁番地区','哈密地区','昌吉回族自治州','博尔塔拉蒙古自治州','巴音郭楞蒙古自治州','阿克苏地区','克孜勒苏柯尔克孜自治州','喀什地区','和田地区','伊犁哈萨克','塔城地区','阿勒泰地区','石河子市','阿拉尔市','图木舒克市','五家渠市'] 41 | }; 42 | 43 | export const areas = { 44 | '北京市':['东城区','西城区','崇文区','宣武区','朝阳区','丰台区','石景山区','海淀区','门头沟区','房山区','通州区','顺义区','昌平区','大兴区','怀柔区','平谷区','密云县','延庆县'], 45 | '天津市':['和平区','河东区','河西区','南开区','河北区','红桥区','塘沽区','汉沽区','大港区','东丽区','西青区','津南区','北辰区','武清区','宝坻区','宁河县','静海县','蓟县'], 46 | '石家庄市':['长安区','桥东区','桥西区','新华区','井陉矿区','裕华区','井陉县','正定县','栾城县','行唐县','灵寿县','高邑县','深泽县','赞皇县','无极县','平山县','元氏县','赵县','辛集市','藁城市','晋州市','新乐市','鹿泉市'], 47 | '唐山市':['路南区','路北区','古冶区','开平区','丰南区','丰润区','滦县','滦南县','乐亭县','迁西县','玉田县','唐海县','遵化市','迁安市'], 48 | '秦皇岛市':['海港区','山海关区','北戴河区','青龙满族自治县','昌黎县','抚宁县','卢龙县'], 49 | '邯郸市':['邯山区','丛台区','复兴区','峰峰矿区','邯郸县','临漳县','成安县','大名县','涉县','磁县','肥乡县','永年县','邱县','鸡泽县','广平县','馆陶县','魏县','曲周县','武安市'], 50 | '邢台市':['桥东区','桥西区','邢台县','临城县','内丘县','柏乡县','隆尧县','任县','南和县','宁晋县','巨鹿县','新河县','广宗县','平乡县','威县','清河县','临西县','南宫市','沙河市'], 51 | '保定市':['新市区','北市区','南市区','满城县','清苑县','涞水县','阜平县','徐水县','定兴县','唐县','高阳县','容城县','涞源县','望都县','安新县','易县','曲阳县','蠡县','顺平县','博野县','雄县','涿州市','定州市','安国市','高碑店市'], 52 | '张家口市':['桥东区','桥西区','宣化区','下花园区','宣化县','张北县','康保县','沽源县','尚义县','蔚县','阳原县','怀安县','万全县','怀来县','涿鹿县','赤城县','崇礼县'], 53 | '承德市':['双桥区','双滦区','鹰手营子矿区','承德县','兴隆县','平泉县','滦平县','隆化县','丰宁满族自治县','宽城满族自治县','围场满族蒙古族自治县'], 54 | '沧州市':['新华区','运河区','沧县','青县','东光县','海兴县','盐山县','肃宁县','南皮县','吴桥县','献县','孟村回族自治县','泊头市','任丘市','黄骅市','河间市'], 55 | '廊坊市':['安次区','广阳区','固安县','永清县','香河县','大城县','文安县','大厂回族自治县','霸州市','三河市'], 56 | '衡水市':['桃城区','枣强县','武邑县','武强县','饶阳县','安平县','故城县','景县','阜城县','冀州市','深州市'], 57 | '太原市':['小店区','迎泽区','杏花岭区','尖草坪区','万柏林区','晋源区','清徐县','阳曲县','娄烦县','古交市'], 58 | '大同市':['城区','矿区','南郊区','新荣区','阳高县','天镇县','广灵县','灵丘县','浑源县','左云县','大同县'], 59 | '阳泉市':['城区','矿区','郊区','平定县','盂县'], 60 | '长治市':['城区','郊区','长治县','襄垣县','屯留县','平顺县','黎城县','壶关县','长子县','武乡县','沁县','沁源县','潞城市'], 61 | '晋城市':['城区','沁水县','阳城县','陵川县','泽州县','高平市'], 62 | '朔州市':['朔城区','平鲁区','山阴县','应县','右玉县','怀仁县'], 63 | '晋中市':['榆次区','榆社县','左权县','和顺县','昔阳县','寿阳县','太谷县','祁县','平遥县','灵石县','介休市'], 64 | '运城市':['盐湖区','临猗县','万荣县','闻喜县','稷山县','新绛县','绛县','垣曲县','夏县','平陆县','芮城县','永济市','河津市'], 65 | '忻州市':['忻府区','定襄县','五台县','代县','繁峙县','宁武县','静乐县','神池县','五寨县','岢岚县','河曲县','保德县','偏关县','原平市'], 66 | '临汾市':['尧都区','曲沃县','翼城县','襄汾县','洪洞县','古县','安泽县','浮山县','吉县','乡宁县','大宁县','隰县','永和县','蒲县','汾西县','侯马市','霍州市'], 67 | '吕梁市':['离石区','文水县','交城县','兴县','临县','柳林县','石楼县','岚县','方山县','中阳县','交口县','孝义市','汾阳市'], 68 | '呼和浩特市':['新城区','回民区','玉泉区','赛罕区','土默特左旗','托克托县','和林格尔县','清水河县','武川县'], 69 | '包头市':['东河区','昆都仑区','青山区','石拐区','白云矿区','九原区','土默特右旗','固阳县','达尔罕茂明安联合旗'], 70 | '乌海市':['海勃湾区','海南区','乌达区'], 71 | '赤峰市':['红山区','元宝山区','松山区','阿鲁科尔沁旗','巴林左旗','巴林右旗','林西县','克什克腾旗','翁牛特旗','喀喇沁旗','宁城县','敖汉旗'], 72 | '通辽市':['科尔沁区','科尔沁左翼中旗','科尔沁左翼后旗','开鲁县','库伦旗','奈曼旗','扎鲁特旗','霍林郭勒市'], 73 | '鄂尔多斯市':['东胜区','达拉特旗','准格尔旗','鄂托克前旗','鄂托克旗','杭锦旗','乌审旗','伊金霍洛旗'], 74 | '呼伦贝尔市':['海拉尔区','阿荣旗','莫力达瓦达斡尔族自治旗','鄂伦春自治旗','鄂温克族自治旗','陈巴尔虎旗','新巴尔虎左旗','新巴尔虎右旗','满洲里市','牙克石市','扎兰屯市','额尔古纳市','根河市'], 75 | '巴彦淖尔市':['临河区','五原县','磴口县','乌拉特前旗','乌拉特中旗','乌拉特后旗','杭锦后旗'], 76 | '乌兰察布市':['集宁区','卓资县','化德县','商都县','兴和县','凉城县','察哈尔右翼前旗','察哈尔右翼中旗','察哈尔右翼后旗','四子王旗','丰镇市'], 77 | '兴安盟':['乌兰浩特市','阿尔山市','科尔沁右翼前旗','科尔沁右翼中旗','扎赉特旗','突泉县'], 78 | '锡林郭勒盟':['二连浩特市','锡林浩特市','阿巴嘎旗','苏尼特左旗','苏尼特右旗','东乌珠穆沁旗','西乌珠穆沁旗','太仆寺旗','镶黄旗','正镶白旗','正蓝旗','多伦县'], 79 | '阿拉善盟':['阿拉善左旗','阿拉善右旗','额济纳旗'], 80 | '沈阳市':['和平区','沈河区','大东区','皇姑区','铁西区','苏家屯区','东陵区','沈北新区','于洪区','辽中县','康平县','法库县','新民市'], 81 | '大连市':['中山区','西岗区','沙河口区','甘井子区','旅顺口区','金州区','长海县','瓦房店市','普兰店市','庄河市'], 82 | '鞍山市':['铁东区','铁西区','立山区','千山区','台安县','岫岩满族自治县','海城市'], 83 | '抚顺市':['新抚区','东洲区','望花区','顺城区','抚顺县','新宾满族自治县','清原满族自治县'], 84 | '本溪市':['平山区','溪湖区','明山区','南芬区','本溪满族自治县','桓仁满族自治县'], 85 | '丹东市':['元宝区','振兴区','振安区','宽甸满族自治县','东港市','凤城市'], 86 | '锦州市':['古塔区','凌河区','太和区','黑山县','义县','凌海市','北镇市'], 87 | '营口市':['站前区','西市区','鲅鱼圈区','老边区','盖州市','大石桥市'], 88 | '阜新市':['海州区','新邱区','太平区','清河门区','细河区','阜新蒙古族自治县','彰武县'], 89 | '辽阳市':['白塔区','文圣区','宏伟区','弓长岭区','太子河区','辽阳县','灯塔市'], 90 | '盘锦市':['双台子区','兴隆台区','大洼县','盘山县'], 91 | '铁岭市':['银州区','清河区','铁岭县','西丰县','昌图县','调兵山市','开原市'], 92 | '朝阳市':['双塔区','龙城区','朝阳县','建平县','喀喇沁左翼蒙古族自治县','北票市','凌源市'], 93 | '葫芦岛市':['连山区','龙港区','南票区','绥中县','建昌县','兴城市'], 94 | '长春市':['南关区','宽城区','朝阳区','二道区','绿园区','双阳区','农安县','九台市','榆树市','德惠市'], 95 | '吉林市':['昌邑区','龙潭区','船营区','丰满区','永吉县','蛟河市','桦甸市','舒兰市','磐石市'], 96 | '四平市':['铁西区','铁东区','梨树县','伊通满族自治县','公主岭市','双辽市'], 97 | '辽源市':['龙山区','西安区','东丰县','东辽县'], 98 | '通化市':['东昌区','二道江区','通化县','辉南县','柳河县','梅河口市','集安市'], 99 | '白山市':['八道江区','江源区','抚松县','靖宇县','长白朝鲜族自治县','临江市'], 100 | '松原市':['宁江区','前郭尔罗斯蒙古族自治县','长岭县','乾安县','扶余县'], 101 | '白城市':['洮北区','镇赉县','通榆县','洮南市','大安市'], 102 | '延边朝鲜族自治州':['延吉市','图们市','敦化市','珲春市','龙井市','和龙市','汪清县','安图县'], 103 | '哈尔滨市':['道里区','南岗区','道外区','平房区','松北区','香坊区','呼兰区','阿城区','依兰县','方正县','宾县','巴彦县','木兰县','通河县','延寿县','双城市','尚志市','五常市'], 104 | '哈尔滨市':['龙沙区','建华区','铁锋区','昂昂溪区','富拉尔基区','碾子山区','梅里斯达斡尔族区','龙江县','依安县','泰来县','甘南县','富裕县','克山县','克东县','拜泉县','讷河市'], 105 | '鸡西市':['鸡冠区','恒山区','滴道区','梨树区','城子河区','麻山区','鸡东县','虎林市','密山市'], 106 | '鹤岗市':['向阳区','工农区','南山区','兴安区','东山区','兴山区','萝北县','绥滨县'], 107 | '双鸭山市':['尖山区','岭东区','四方台区','宝山区','集贤县','友谊县','宝清县','饶河县'], 108 | '大庆市':['萨尔图区','龙凤区','让胡路区','红岗区','大同区','肇州县','肇源县','林甸县','杜尔伯特蒙古族自治县'], 109 | '伊春市':['伊春区','南岔区','友好区','西林区','翠峦区','新青区','美溪区','金山屯区','五营区','乌马河区','汤旺河区','带岭区','乌伊岭区','红星区','上甘岭区','嘉荫县','铁力市'], 110 | '佳木斯市':['向阳区','前进区','东风区','郊区','桦南县','桦川县','汤原县','抚远县','同江市','富锦市'], 111 | '七台河市':['新兴区','桃山区','茄子河区','勃利县'], 112 | '牡丹江市':['东安区','阳明区','爱民区','西安区','东宁县','林口县','绥芬河市','海林市','宁安市','穆棱市'], 113 | '黑河市':['爱辉区','嫩江县','逊克县','孙吴县','北安市','五大连池市'], 114 | '绥化市':['北林区','望奎县','兰西县','青冈县','庆安县','明水县','绥棱县','安达市','肇东市','海伦市'], 115 | '大兴安岭地区':['加格达奇区','松岭区','新林区','呼中区','呼玛县','塔河县','漠河县'], 116 | '上海市':['黄浦区','卢湾区','徐汇区','长宁区','静安区','普陀区','闸北区','虹口区','杨浦区','闵行区','宝山区','嘉定区','浦东新区','金山区','松江区','青浦区','南汇区','奉贤区','崇明县'], 117 | '南京市':['玄武区','白下区','秦淮区','建邺区','鼓楼区','下关区','浦口区','栖霞区','雨花台区','江宁区','六合区','溧水县','高淳县'], 118 | '无锡市':['崇安区','南长区','北塘区','锡山区','惠山区','滨湖区','江阴市','宜兴市'], 119 | '徐州市':['鼓楼区','云龙区','九里区','贾汪区','泉山区','丰县','沛县','铜山县','睢宁县','新沂市','邳州市'], 120 | '常州市':['天宁区','钟楼区','戚墅堰区','新北区','武进区','溧阳市','金坛市'], 121 | '苏州市':['沧浪区','平江区','金阊区','虎丘区','吴中区','相城区','常熟市','张家港市','昆山市','吴江市','太仓市'], 122 | '南通市':['崇川区','港闸区','海安县','如东县','启东市','如皋市','通州市','海门市'], 123 | '连云港市':['连云区','新浦区','海州区','赣榆县','东海县','灌云县','灌南县'], 124 | '淮安市':['清河区','楚州区','淮阴区','清浦区','涟水县','洪泽县','盱眙县','金湖县'], 125 | '盐城市':['亭湖区','盐都区','响水县','滨海县','阜宁县','射阳县','建湖县','东台市','大丰市'], 126 | '扬州市':['广陵区','邗江区','维扬区','宝应县','仪征市','高邮市','江都市'], 127 | '镇江市':['京口区','润州区','丹徒区','丹阳市','扬中市','句容市'], 128 | '泰州市':['海陵区','高港区','兴化市','靖江市','泰兴市','姜堰市'], 129 | '宿迁市':['宿城区','宿豫区','沭阳县','泗阳县','泗洪县'], 130 | '杭州市':['上城区','下城区','江干区','拱墅区','西湖区','滨江区','萧山区','余杭区','桐庐县','淳安县','建德市','富阳市','临安市'], 131 | '宁波市':['海曙区','江东区','江北区','北仑区','镇海区','鄞州区','象山县','宁海县','余姚市','慈溪市','奉化市'], 132 | '温州市':['鹿城区','龙湾区','瓯海区','洞头县','永嘉县','平阳县','苍南县','文成县','泰顺县','瑞安市','乐清市'], 133 | '嘉兴市':['秀城区','秀洲区','嘉善县','海盐县','海宁市','平湖市','桐乡市'], 134 | '湖州市':['吴兴区','南浔区','德清县','长兴县','安吉县'], 135 | '绍兴市':['越城区','绍兴县','新昌县','诸暨市','上虞市','嵊州市'], 136 | '金华市':['婺城区','金东区','武义县','浦江县','磐安县','兰溪市','义乌市','东阳市','永康市'], 137 | '衢州市':['柯城区','衢江区','常山县','开化县','龙游县','江山市'], 138 | '舟山市':['定海区','普陀区','岱山县','嵊泗县'], 139 | '台州市':['椒江区','黄岩区','路桥区','玉环县','三门县','天台县','仙居县','温岭市','临海市'], 140 | '丽水市':['莲都区','青田县','缙云县','遂昌县','松阳县','云和县','庆元县','景宁畲族自治县','龙泉市'], 141 | '合肥市':['瑶海区','庐阳区','蜀山区','包河区','长丰县','肥东县','肥西县'], 142 | '芜湖市':['镜湖区','弋江区','鸠江区','三山区','芜湖县','繁昌县','南陵县'], 143 | '蚌埠市':['龙子湖区','蚌山区','禹会区','淮上区','怀远县','五河县','固镇县'], 144 | '淮南市':['大通区','田家庵区','谢家集区','八公山区','潘集区','凤台县'], 145 | '马鞍山市':['金家庄区','花山区','雨山区','当涂县'], 146 | '淮北市':['杜集区','相山区','烈山区','濉溪县'], 147 | '铜陵市':['铜官山区','狮子山区','郊区','铜陵县'], 148 | '安庆市':['迎江区','大观区','宜秀区','怀宁县','枞阳县','潜山县','太湖县','宿松县','望江县','岳西县','桐城市'], 149 | '黄山市':['屯溪区','黄山区','徽州区','歙县','休宁县','黟县','祁门县'], 150 | '滁州市':['琅琊区','南谯区','来安县','全椒县','定远县','凤阳县','天长市','明光市'], 151 | '阜阳市':['颍州区','颍东区','颍泉区','临泉县','太和县','阜南县','颍上县','颍上县'], 152 | '宿州市':['埇桥区','砀山县','萧县','灵璧县','泗县'], 153 | '巢湖市':['居巢区','庐江县','无为县','含山县','和县'], 154 | '六安市':['金安区','裕安区','寿县','霍邱县','舒城县','金寨县','霍山县'], 155 | '亳州市':['谯城区','涡阳县','蒙城县','利辛县'], 156 | '池州市':['贵池区','东至县','石台县','青阳县'], 157 | '宣城市':['宣州区','郎溪县','广德县','泾县','绩溪县','旌德县','宁国市'], 158 | '福州市':['鼓楼区','台江区','仓山区','马尾区','晋安区','闽侯县','连江县','罗源县','闽清县','永泰县','平潭县','福清市','长乐市'], 159 | '厦门市':['思明区','海沧区','湖里区','集美区','同安区','翔安区'], 160 | '莆田市':['城厢区','涵江区','荔城区','秀屿区','仙游县'], 161 | '三明市':['梅列区','三元区','明溪县','清流县','宁化县','大田县','尤溪县','沙县','将乐县','泰宁县','建宁县','永安市'], 162 | '泉州市':['鲤城区','丰泽区','洛江区','泉港区','惠安县','安溪县','永春县','德化县','金门县','石狮市','晋江市','南安市'], 163 | '漳州市':['芗城区','龙文区','云霄县','漳浦县','诏安县','长泰县','东山县','南靖县','平和县','华安县','龙海市'], 164 | '南平市':['延平区','顺昌县','浦城县','光泽县','松溪县','政和县','邵武市','武夷山市','建瓯市','建阳市'], 165 | '龙岩市':['新罗区','长汀县','永定县','上杭县','武平县','连城县','漳平市'], 166 | '宁德市':['蕉城区','霞浦县','古田县','屏南县','寿宁县','周宁县','柘荣县','福安市','福鼎市'], 167 | '南昌市':['东湖区','西湖区','青云谱区','湾里区','青山湖区','南昌县','新建县','安义县','进贤县'], 168 | '景德镇市':['昌江区','珠山区','浮梁县','乐平市'], 169 | '萍乡市':['安源区','湘东区','莲花县','上栗县','芦溪县'], 170 | '九江市':['庐山区','浔阳区','九江县','武宁县','修水县','永修县','德安县','星子县','都昌县','湖口县','彭泽县','瑞昌市'], 171 | '新余市':['渝水区','分宜县'], 172 | '鹰潭市':['月湖区','余江县','贵溪市'], 173 | '赣州市':['章贡区','赣县','信丰县','大余县','上犹县','崇义县','安远县','龙南县','定南县','全南县','宁都县','于都县','兴国县','会昌县','寻乌县','石城县','瑞金市','南康市'], 174 | '吉安市':['吉州区','青原区','吉安县','吉水县','峡江县','新干县','永丰县','泰和县','遂川县','万安县','安福县','永新县','井冈山市'], 175 | '宜春市':['袁州区','奉新县','万载县','上高县','宜丰县','靖安县','铜鼓县','丰城市','樟树市','高安市'], 176 | '抚州市':['临川区','南城县','黎川县','南丰县','崇仁县','乐安县','宜黄县','金溪县','资溪县','东乡县','广昌县'], 177 | '上饶市':['信州区','上饶县','广丰县','玉山县','铅山县','横峰县','弋阳县','余干县','鄱阳县','万年县','婺源县','德兴市'], 178 | '济南市':['历下区','市中区','槐荫区','天桥区','历城区','长清区','平阴县','济阳县','商河县','章丘市'], 179 | '青岛市':['市南区','市北区','四方区','黄岛区','崂山区','李沧区','城阳区','胶州市','即墨市','平度市','胶南市','莱西市'], 180 | '淄博市':['淄川区','张店区','博山区','临淄区','周村区','桓台县','高青县','沂源县'], 181 | '枣庄市':['市中区','薛城区','峄城区','台儿庄区','山亭区','滕州市'], 182 | '东营市':['东营区','河口区','垦利县','利津县','广饶县'], 183 | '烟台市':['芝罘区','福山区','牟平区','莱山区','长岛县','龙口市','莱阳市','莱州市','蓬莱市','招远市','栖霞市','海阳市'], 184 | '潍坊市':['潍城区','寒亭区','坊子区','奎文区','临朐县','昌乐县','青州市','诸城市','寿光市','安丘市','高密市','昌邑市'], 185 | '济宁市':['市中区','任城区','微山县','鱼台县','金乡县','嘉祥县','汶上县','泗水县','梁山县','曲阜市','兖州市','邹城市'], 186 | '泰安市':['泰山区','岱岳区','宁阳县','东平县','新泰市','肥城市'], 187 | '威海市':['环翠区','文登市','荣成市','乳山市'], 188 | '日照市':['东港区','岚山区','五莲县','莒县'], 189 | '莱芜市':['莱城区','钢城区'], 190 | '临沂市':['兰山区','罗庄区','河东区','沂南县','郯城县','沂水县','苍山县','费县','平邑县','莒南县','蒙阴县','临沭县'], 191 | '德州市':['德城区','陵县','宁津县','庆云县','临邑县','齐河县','平原县','夏津县','武城县','乐陵市','禹城市'], 192 | '聊城市':['东昌府区','阳谷县','莘县','茌平县','东阿县','冠县','高唐县','临清市'], 193 | '滨州市':['滨城区','惠民县','阳信县','无棣县','沾化县','博兴县','邹平县'], 194 | '菏泽市':['牡丹区','曹县','单县','成武县','巨野县','郓城县','鄄城县','定陶县','东明县'], 195 | '郑州市':['中原区','二七区','管城回族区','金水区','上街区','惠济区','中牟县','巩义市','荥阳市','新密市','新郑市','登封市'], 196 | '开封市':['龙亭区','顺河回族区','鼓楼区','禹王台区','金明区','杞县','通许县','尉氏县','开封县','兰考县'], 197 | '洛阳市':['老城区','西工区','廛河回族区','涧西区','吉利区','洛龙区','孟津县','新安县','栾川县','嵩县','汝阳县','宜阳县','洛宁县','伊川县','偃师市'], 198 | '平顶山市':['新华区','卫东区','石龙区','湛河区','宝丰县','叶县','鲁山县','郏县','舞钢市','汝州市'], 199 | '安阳市':['文峰区','北关区','殷都区','龙安区','安阳县','汤阴县','滑县','内黄县','林州市'], 200 | '鹤壁市':['鹤山区','山城区','淇滨区','浚县','淇县'], 201 | '新乡市':['红旗区','卫滨区','凤泉区','牧野区','新乡县','获嘉县','原阳县','延津县','封丘县','长垣县','卫辉市','辉县市'], 202 | '焦作市':['解放区','中站区','马村区','山阳区','修武县','博爱县','武陟县','温县','济源市','沁阳市','孟州市'], 203 | '濮阳市':['华龙区','清丰县','南乐县','范县','台前县','濮阳县'], 204 | '许昌市':['魏都区','许昌县','鄢陵县','襄城县','禹州市','长葛市'], 205 | '漯河市':['源汇区','郾城区','召陵区','舞阳县','临颍县'], 206 | '三门峡市':['湖滨区','渑池县','陕县','卢氏县','义马市','灵宝市'], 207 | '南阳市':['宛城区','卧龙区','南召县','方城县','西峡县','镇平县','内乡县','淅川县','社旗县','唐河县','新野县','桐柏县','邓州市'], 208 | '商丘市':['梁园区','睢阳区','民权县','睢县','宁陵县','柘城县','虞城县','夏邑县','永城市'], 209 | '信阳市':['浉河区','平桥区','罗山县','光山县','新县','商城县','固始县','潢川县','淮滨县','息县'], 210 | '周口市':['川汇区','扶沟县','西华县','商水县','沈丘县','郸城县','淮阳县','太康县','鹿邑县','项城市'], 211 | '驻马店市':['驿城区','西平县','上蔡县','平舆县','正阳县','确山县','泌阳县','汝南县','遂平县','新蔡县'], 212 | '武汉市':['江岸区','江汉区','硚口区','汉阳区','武昌区','青山区','洪山区','东西湖区','汉南区','蔡甸区','江夏区','黄陂区','新洲区'], 213 | '黄石市':['黄石港区','西塞山区','下陆区','铁山区','阳新县','大冶市'], 214 | '十堰市':['茅箭区','张湾区','郧县','郧西县','竹山县','竹溪县','房县','丹江口市'], 215 | '宜昌市':['西陵区','伍家岗区','点军区','猇亭区','夷陵区','远安县','兴山县','秭归县','长阳土家族自治县','五峰土家族自治县','宜都市','当阳市','枝江市'], 216 | '襄樊市':['襄城区','樊城区','襄阳区','南漳县','谷城县','保康县','老河口市','枣阳市','宜城市'], 217 | '鄂州市':['梁子湖区','华容区','鄂城区'], 218 | '荆门市':['东宝区','掇刀区','京山县','沙洋县','钟祥市'], 219 | '孝感市':['孝南区','孝昌县','大悟县','云梦县','应城市','安陆市','汉川市'], 220 | '荆州市':['沙市区','荆州区','公安县','监利县','江陵县','石首市','洪湖市','松滋市'], 221 | '黄冈市':['黄州区','团风县','红安县','罗田县','英山县','浠水县','蕲春县','黄梅县','麻城市','武穴市'], 222 | '咸宁市':['咸安区','嘉鱼县','通城县','崇阳县','通山县','赤壁市'], 223 | '随州市':['曾都区','广水市'], 224 | '恩施土家族苗族自治州':['恩施市','利川市','建始县','巴东县','宣恩县','咸丰县','来凤县','鹤峰县'], 225 | '直辖行政单位':['仙桃市','潜江市','天门市','神农架林区'], 226 | '长沙市':['芙蓉区','天心区','岳麓区','开福区','雨花区','长沙县','望城县','宁乡县','浏阳市'], 227 | '株洲市':['荷塘区','芦淞区','石峰区','天元区','株洲县','攸县','茶陵县','炎陵县','醴陵市'], 228 | '湘潭市':['雨湖区','岳塘区','湘潭县','湘乡市','韶山市'], 229 | '衡阳市':['珠晖区','雁峰区','石鼓区','蒸湘区','南岳区','衡阳县','衡南县','衡山县','衡东县','祁东县','耒阳市','常宁市'], 230 | '邵阳市':['双清区','大祥区','北塔区','邵东县','新邵县','邵阳县','隆回县','洞口县','绥宁县','新宁县','城步苗族自治县','武冈市'], 231 | '岳阳市':['岳阳楼区','云溪区','君山区','岳阳县','华容县','湘阴县','平江县','汨罗市','临湘市'], 232 | '常德市':['武陵区','鼎城区','安乡县','汉寿县','澧县','临澧县','桃源县','石门县','津市市'], 233 | '张家界市':['永定区','武陵源区','慈利县','桑植县'], 234 | '益阳市':['资阳区','赫山区','南县','桃江县','安化县','沅江市'], 235 | '郴州市':['北湖区','苏仙区','桂阳县','宜章县','永兴县','嘉禾县','临武县','汝城县','桂东县','安仁县','资兴市'], 236 | '永州市':['零陵区','冷水滩区','祁阳县','东安县','双牌县','道县','江永县','宁远县','蓝山县','新田县','江华瑶族自治县'], 237 | '怀化市':['鹤城区','中方县','沅陵县','辰溪县','溆浦县','会同县','麻阳苗族自治县','新晃侗族自治县','芷江侗族自治县','靖州苗族侗族自治县','通道侗族自治县','洪江市'], 238 | '娄底市':['娄星区','双峰县','新化县','冷水江市','涟源市'], 239 | '湘西土家族苗族自治州':['吉首市','泸溪县','凤凰县','花垣县','保靖县','古丈县','永顺县','龙山县'], 240 | '广州市':['荔湾区','越秀区','海珠区','天河区','白云区','黄埔区','番禺区','花都区','南沙区','萝岗区','增城市','从化市'], 241 | '韶关市':['武江区','浈江区','曲江区','始兴县','仁化县','翁源县','乳源瑶族自治县','新丰县','乐昌市','南雄市'], 242 | '深圳市':['罗湖区','福田区','南山区','宝安区','龙岗区','盐田区'], 243 | '珠海市':['香洲区','斗门区','金湾区'], 244 | '汕头市':['龙湖区','金平区','濠江区','潮阳区','潮南区','澄海区','南澳县'], 245 | '佛山市':['禅城区','南海区','顺德区','三水区','高明区'], 246 | '江门市':['蓬江区','江海区','新会区','台山市','开平市','鹤山市','恩平市'], 247 | '湛江市':['赤坎区','霞山区','坡头区','麻章区','遂溪县','徐闻县','廉江市','雷州市','吴川市'], 248 | '茂名市':['茂南区','茂港区','电白县','高州市','化州市','信宜市'], 249 | '肇庆市':['端州区','鼎湖区','广宁县','怀集县','封开县','德庆县','高要市','四会市'], 250 | '惠州市':['惠城区','惠阳区','博罗县','惠东县','龙门县'], 251 | '梅州市':['梅江区','梅县','大埔县','丰顺县','五华县','平远县','蕉岭县','兴宁市'], 252 | '汕尾市':['城区','海丰县','陆河县','陆丰市'], 253 | '河源市':['源城区','紫金县','龙川县','连平县','和平县','东源县'], 254 | '阳江市':['江城区','阳西县','阳东县','阳春市'], 255 | '清远市':['清城区','佛冈县','阳山县','连山壮族瑶族自治县','连南瑶族自治县','清新县','英德市','连州市'], 256 | '东莞市':['市辖区'], 257 | '中山市':['市辖区'], 258 | '潮州市':['湘桥区','潮安县','饶平县'], 259 | '揭阳市':['榕城区','揭东县','揭西县','惠来县','普宁市'], 260 | '云浮市':['云城区','新兴县','郁南县','云安县','罗定市'], 261 | '南宁市':['兴宁区','青秀区','江南区','西乡塘区','良庆区','邕宁区','武鸣县','隆安县','马山县','上林县','宾阳县','横县'], 262 | '柳州市':['城中区','鱼峰区','柳南区','柳北区','柳江县','柳城县','鹿寨县','融安县','融水苗族自治县','三江侗族自治县'], 263 | '桂林市':['秀峰区','叠彩区','象山区','七星区','雁山区','阳朔县','临桂县','灵川县','全州县','兴安县','永福县','灌阳县','龙胜各族自治县','资源县','平乐县','荔蒲县','恭城瑶族自治县'], 264 | '梧州市':['万秀区','蝶山区','长洲区','苍梧县','藤县','蒙山县','岑溪市'], 265 | '北海市':['海城区','银海区','铁山港区','合浦县'], 266 | '防城港市':['港口区','防城区','上思县','东兴市'], 267 | '钦州市':['钦南区','钦北区','灵山县','浦北县'], 268 | '贵港市':['港北区','港南区','覃塘区','平南县','桂平市'], 269 | '玉林市':['玉州区','容县','陆川县','博白县','兴业县','北流市'], 270 | '百色市':['右江区','田阳县','田东县','平果县','德保县','靖西县','那坡县','凌云县','乐业县','田林县','西林县','隆林各族自治县'], 271 | '贺州市':['八步区','昭平县','钟山县','富川瑶族自治县'], 272 | '河池市':['金城江区','南丹县','天峨县','凤山县','东兰县','罗城仫佬族自治县','环江毛南族自治县','巴马瑶族自治县','都安瑶族自治县','大化瑶族自治县','宜州市'], 273 | '来宾市':['兴宾区','忻城县','象州县','武宣县','金秀瑶族自治县','合山市'], 274 | '崇左市':['江洲区','扶绥县','宁明县','龙州县','大新县','天等县','凭祥市'], 275 | '海口市':['秀英区','龙华区','琼山区','美兰区'], 276 | '三亚市':['直辖县级行政单位','五指山市','琼海市','儋州市','文昌市','万宁市','东方市','定安县','屯昌县','澄迈县','临高县','白沙黎族自治县','昌江黎族自治县','乐东黎族自治县','陵水黎族自治县','保亭黎族苗族自治县','琼中黎族苗族自治县','西沙群岛','南沙群岛','中沙群岛的岛礁及其海域'], 277 | '市辖区':['万州区','涪陵区','渝中区','大渡口区','江北区','沙坪坝区','九龙坡区','南岸区','北碚区','万盛区','双桥区','渝北区','巴南区','黔江区','长寿区','江津区','合川区','永川区','永川区'], 278 | '县':['綦江县','潼南县','铜梁县','大足县','荣昌县','璧山县','梁平县','城口县','丰都县','垫江县','武隆县','忠县','开县','云阳县','奉节县','巫山县','巫溪县','石柱土家族自治县','秀山土家族苗族自治县','酉阳土家族苗族自治县','彭水苗族土家族自治县'], 279 | '成都市':['锦江区','青羊区','金牛区','武侯区','成华区','龙泉驿区','青白江区','新都区','温江区','金堂县','双流县','郫县','大邑县','蒲江县','新津县','都江堰市','彭州市','邛崃市','崇州市'], 280 | '自贡市':['自流井区','贡井区','大安区','沿滩区','荣县','富顺县'], 281 | '攀枝花市':['东区','西区','仁和区','米易县','盐边县'], 282 | '泸州市':['江阳区','纳溪区','龙马潭区','泸县','合江县','叙永县','古蔺县'], 283 | '德阳市':['旌阳区','中江县','罗江县','广汉市','什邡市','绵竹市'], 284 | '绵阳市':['涪城区','游仙区','三台县','盐亭县','安县','梓潼县','北川羌族自治县','平武县','江油市'], 285 | '广元市':['市中区','元坝区','朝天区','旺苍县','青川县','剑阁县','苍溪县'], 286 | '遂宁市':['船山区','安居区','蓬溪县','射洪县','大英县'], 287 | '内江市':['市中区','东兴区','威远县','资中县','隆昌县'], 288 | '乐山市':['市中区','沙湾区','五通桥区','金口河区','犍为县','井研县','夹江县','沐川县','峨边彝族自治县','马边彝族自治县','峨眉山市'], 289 | '南充市':['顺庆区','高坪区','嘉陵区','南部县','营山县','蓬安县','仪陇县','西充县','阆中市'], 290 | '眉山市':['东坡区','仁寿县','彭山县','洪雅县','丹棱县','青神县'], 291 | '宜宾市':['翠屏区','宜宾县','南溪县','江安县','长宁县','高县','珙县','筠连县','兴文县','屏山县'], 292 | '广安市':['广安区','岳池县','武胜县','邻水县','华蓥市'], 293 | '达州市':['通川区','达县','宣汉县','开江县','大竹县','渠县','万源市'], 294 | '雅安市':['雨城区','名山县','荥经县','汉源县','石棉县','天全县','芦山县','宝兴县'], 295 | '巴中市':['巴州区','通江县','南江县','平昌县'], 296 | '资阳市':['雁江区','安岳县','乐至县','简阳市'], 297 | '阿坝藏族羌族自治州':['汶川县','理县','茂县','松潘县','九寨沟县','金川县','小金县','黑水县','马尔康县','壤塘县','阿坝县','若尔盖县','红原县'], 298 | '甘孜藏族自治州':['康定县','泸定县','丹巴县','九龙县','雅江县','道孚县','炉霍县','甘孜县','新龙县','德格县','白玉县','石渠县','色达县','理塘县','巴塘县','乡城县','稻城县','得荣县'], 299 | '凉山彝族自治州':['西昌市','木里藏族自治县','盐源县','德昌县','会理县','会东县','宁南县','普格县','布拖县','金阳县','昭觉县','喜德县','冕宁县','越西县','甘洛县','美姑县','雷波县'], 300 | '贵阳市':['南明区','云岩区','花溪区','乌当区','白云区','小河区','开阳县','息烽县','修文县','清镇市'], 301 | '六盘水市':['钟山区','六枝特区','水城县','盘县'], 302 | '遵义市':['红花岗区','汇川区','遵义县','桐梓县','绥阳县','正安县','道真仡佬族苗族自治县','务川仡佬族苗族自治县','凤冈县','湄潭县','余庆县','习水县','赤水市','仁怀市'], 303 | '安顺市':['西秀区','平坝县','普定县','镇宁布依族苗族自治县','关岭布依族苗族自治县','紫云苗族布依族自治县'], 304 | '铜仁地区':['铜仁市','江口县','玉屏侗族自治县','石阡县','思南县','印江土家族苗族自治县','德江县','沿河土家族自治县','松桃苗族自治县','万山特区'], 305 | '黔西南布依族苗族自治州':['兴义市','兴仁县','普安县','晴隆县','贞丰县','望谟县','册亨县','安龙县'], 306 | '毕节地区':['毕节市','大方县','黔西县','金沙县','织金县','纳雍县','威宁彝族回族苗族自治县','赫章县'], 307 | '黔东南苗族侗族自治州':['凯里市','黄平县','施秉县','三穗县','镇远县','岑巩县','天柱县','锦屏县','剑河县','台江县','黎平县','榕江县','从江县','雷山县','麻江县','丹寨县'], 308 | '黔南布依族苗族自治州':['都匀市','福泉市','荔波县','贵定县','瓮安县','独山县','平塘县','罗甸县','长顺县','龙里县','惠水县','三都水族自治县'], 309 | '昆明市':['五华区','盘龙区','官渡区','西山区','东川区','呈贡县','晋宁县','富民县','宜良县','石林彝族自治县','嵩明县','禄劝彝族苗族自治县','寻甸回族彝族自治县','安宁市'], 310 | '曲靖市':['麒麟区','马龙县','陆良县','师宗县','罗平县','富源县','会泽县','沾益县','宣威市'], 311 | '玉溪市':['红塔区','江川县','澄江县','通海县','华宁县','易门县','峨山彝族自治县','新平彝族傣族自治县','元江哈尼族彝族傣族自治县'], 312 | '保山市':['隆阳区','施甸县','腾冲县','龙陵县','昌宁县'], 313 | '昭通市':['昭阳区','鲁甸县','巧家县','盐津县','大关县','永善县','绥江县','镇雄县','彝良县','威信县','水富县'], 314 | '丽江市':['古城区','玉龙纳西族自治县','永胜县','华坪县','宁蒗彝族自治县'], 315 | '思茅市':['翠云区','普洱哈尼族彝族自治县','墨江哈尼族自治县','景东彝族自治县','景谷傣族彝族自治县','镇沅彝族哈尼族拉祜族自治县','江城哈尼族彝族自治县','孟连傣族拉祜族佤族自治县','澜沧拉祜族自治县','西盟佤族自治县'], 316 | '临沧市':['临翔区','凤庆县','云县','永德县','镇康县','双江拉祜族佤族布朗族傣族自治县','耿马傣族佤族自治县','沧源佤族自治县'], 317 | '楚雄彝族自治州':['楚雄市','双柏县','牟定县','南华县','姚安县','大姚县','永仁县','元谋县','武定县','禄丰县'], 318 | '红河哈尼族彝族自治州':['个旧市','开远市','蒙自县','屏边苗族自治县','建水县','石屏县','弥勒县','泸西县','元阳县','红河县','金平苗族瑶族傣族自治县','绿春县','河口瑶族自治县'], 319 | '文山壮族苗族自治州':['文山县','砚山县','西畴县','麻栗坡县','马关县','丘北县','广南县','富宁县'], 320 | '西双版纳傣族自治州':['景洪市','勐海县','勐腊县'], 321 | '大理白族自治州':['大理市','漾濞彝族自治县','祥云县','宾川县','弥渡县','南涧彝族自治县','巍山彝族回族自治县','永平县','云龙县','洱源县','剑川县','鹤庆县'], 322 | '德宏傣族景颇族自治州':['瑞丽市','潞西市','梁河县','盈江县','陇川县'], 323 | '怒江傈僳族自治州':['泸水县','福贡县','贡山独龙族怒族自治县','兰坪白族普米族自治县'], 324 | '迪庆藏族自治州':['香格里拉县','德钦县','维西傈僳族自治县'], 325 | '拉萨市':['城关区','林周县','当雄县','尼木县','曲水县','堆龙德庆县','达孜县','墨竹工卡县'], 326 | '昌都地区':['昌都县','江达县','贡觉县','类乌齐县','丁青县','察雅县','八宿县','左贡县','芒康县','洛隆县','边坝县'], 327 | '山南地区':['乃东县','扎囊县','贡嘎县','桑日县','琼结县','曲松县','措美县','洛扎县','加查县','隆子县','错那县','浪卡子县'], 328 | '日喀则地区':['日喀则市','南木林县','江孜县','定日县','萨迦县','拉孜县','昂仁县','谢通门县','白朗县','仁布县','康马县','定结县','仲巴县','亚东县','吉隆县','聂拉木县','萨嘎县','岗巴县'], 329 | '那曲地区':['那曲县','嘉黎县','比如县','聂荣县','安多县','申扎县','索县','班戈县','巴青县','尼玛县'], 330 | '阿里地区':['普兰县','札达县','噶尔县','日土县','革吉县','改则县','措勤县'], 331 | '林芝地区':['林芝县','工布江达县','米林县','墨脱县','波密县','察隅县','朗县'], 332 | '西安市':['新城区','碑林区','莲湖区','灞桥区','未央区','雁塔区','阎良区','临潼区','长安区','蓝田县','周至县','户县','高陵县'], 333 | '铜川市':['王益区','印台区','耀州区','宜君县'], 334 | '宝鸡市':['渭滨区','金台区','陈仓区','凤翔县','岐山县','扶风县','眉县','陇县','千阳县','麟游县','凤县','太白县'], 335 | '咸阳市':['秦都区','杨凌区','渭城区','三原县','泾阳县','乾县','礼泉县','永寿县','彬县','长武县','旬邑县','淳化县','武功县','兴平市'], 336 | '渭南市':['临渭区','华县','潼关县','大荔县','合阳县','澄城县','蒲城县','白水县','富平县','韩城市','华阴市'], 337 | '延安市':['宝塔区','延长县','延川县','子长县','安塞县','志丹县','吴起县','甘泉县','富县','洛川县','宜川县','黄龙县','黄陵县'], 338 | '汉中市':['汉台区','南郑县','城固县','洋县','西乡县','勉县','宁强县','略阳县','镇巴县','留坝县','佛坪县'], 339 | '榆林市':['榆阳区','神木县','府谷县','横山县','靖边县','定边县','绥德县','米脂县','佳县','吴堡县','清涧县','子洲县'], 340 | '安康市':['汉滨区','汉阴县','石泉县','宁陕县','紫阳县','岚皋县','平利县','镇坪县','旬阳县','白河县'], 341 | '商洛市':['商州区','洛南县','丹凤县','商南县','山阳县','镇安县','柞水县'], 342 | '兰州市':['城关区','七里河区','西固区','安宁区','红古区','永登县','皋兰县','榆中县'], 343 | '嘉峪关市':[''], 344 | '金昌市':['金川区','永昌县'], 345 | '白银市':['白银区','平川区','靖远县','会宁县','景泰县'], 346 | '天水市':['秦城区','北道区','清水县','秦安县','甘谷县','武山县','张家川回族自治县'], 347 | '武威市':['凉州区','民勤县','古浪县','天祝藏族自治县'], 348 | '张掖市':['甘州区','肃南裕固族自治县','民乐县','临泽县','高台县','山丹县'], 349 | '平凉市':['崆峒区','泾川县','灵台县','崇信县','华亭县','庄浪县','静宁县'], 350 | '酒泉市':['肃州区','金塔县','瓜州县','肃北蒙古族自治县','阿克塞哈萨克族自治县','玉门市','敦煌市'], 351 | '庆阳市':['西峰区','庆城县','环县','华池县','合水县','正宁县','宁县','镇原县'], 352 | '定西市':['安定区','通渭县','陇西县','渭源县','临洮县','漳县','岷县'], 353 | '陇南市':['武都区','成县','文县','宕昌县','康县','西和县','礼县','徽县','两当县'], 354 | '临夏回族自治州':['临夏市','临夏县','康乐县','永靖县','广河县','和政县','东乡族自治县','积石山保安族东乡族撒拉族自治县'], 355 | '甘南藏族自治州':['合作市','临潭县','卓尼县','舟曲县','迭部县','玛曲县','碌曲县','夏河县'], 356 | '西宁市':['城东区','城中区','城西区','城北区','大通回族土族自治县','湟中县','湟源县'], 357 | '海东地区':['平安县','民和回族土族自治县','乐都县','互助土族自治县','化隆回族自治县','循化撒拉族自治县'], 358 | '海北藏族自治州':['门源回族自治县','祁连县','海晏县','刚察县'], 359 | '黄南藏族自治州':['同仁县','尖扎县','泽库县','河南蒙古族自治县'], 360 | '海南藏族自治州':['共和县','同德县','贵德县','兴海县','贵南县'], 361 | '果洛藏族自治州':['玛沁县','班玛县','甘德县','达日县','久治县','玛多县'], 362 | '玉树藏族自治州':['玉树县','杂多县','称多县','治多县','囊谦县','曲麻莱县'], 363 | '海西蒙古族藏族自治州':['格尔木市','德令哈市','乌兰县','都兰县','天峻县'], 364 | '银川市':['兴庆区','西夏区','金凤区','永宁县','贺兰县','灵武市'], 365 | '石嘴山市':['大武口区','惠农区','平罗县'], 366 | '吴忠市':['利通区','盐池县','同心县','青铜峡市'], 367 | '固原市':['原州区','西吉县','隆德县','泾源县','彭阳县'], 368 | '中卫市':['沙坡头区','中宁县','海原县'], 369 | '乌鲁木齐市':['天山区','沙依巴克区','新市区','水磨沟区','头屯河区','达坂城区','东山区','乌鲁木齐县'], 370 | '克拉玛依市':['独山子区','克拉玛依区','白碱滩区','乌尔禾区'], 371 | '吐鲁番地区':['吐鲁番市','鄯善县','托克逊县'], 372 | '哈密地区':['哈密市','巴里坤哈萨克自治县','伊吾县'], 373 | '昌吉回族自治州':['昌吉市','阜康市','米泉市','呼图壁县','玛纳斯县','奇台县','吉木萨尔县','木垒哈萨克自治县'], 374 | '博尔塔拉蒙古自治州':['博乐市','精河县','温泉县'], 375 | '巴音郭楞蒙古自治州':['库尔勒市','轮台县','尉犁县','若羌县','且末县','焉耆回族自治县','和静县','和硕县','博湖县'], 376 | '阿克苏地区':['阿克苏市','温宿县','库车县','沙雅县','新和县','拜城县','乌什县','阿瓦提县','柯坪县'], 377 | '克孜勒苏柯尔克孜自治州':['阿图什市','阿克陶县','阿合奇县','乌恰县'], 378 | '喀什地区':['喀什市','疏附县','疏勒县','英吉沙县','泽普县','莎车县','叶城县','麦盖提县','岳普湖县','伽师县','巴楚县','塔什库尔干塔吉克自治县'], 379 | '和田地区':['和田市','和田县','墨玉县','皮山县','洛浦县','策勒县','于田县','民丰县'], 380 | '伊犁哈萨克':['伊宁市','奎屯市','伊宁县','察布查尔锡伯自治县','霍城县','巩留县','新源县','昭苏县','特克斯县','尼勒克县'], 381 | '塔城地区':['塔城市','乌苏市','额敏县','沙湾县','托里县','裕民县','和布克赛尔蒙古自治县'], 382 | '阿勒泰地区':['阿勒泰市','布尔津县','富蕴县','福海县','哈巴河县','青河县','吉木乃县'], 383 | '石河子市':[''], 384 | '阿拉尔市':[''], 385 | '图木舒克市':[''], 386 | '五家渠市':[''] 387 | }; 388 | -------------------------------------------------------------------------------- /src/components-ext/picker-address/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Picker, Popup } from '../../components'; 4 | import { provins, citys, areas } from './address'; 5 | import './index.scss'; 6 | 7 | const propTypes = { 8 | defaultValue: PropTypes.array.isRequired, 9 | onConfirm: PropTypes.func.isRequired, 10 | onCancel: PropTypes.func.isRequired, 11 | onChange: PropTypes.func.isRequired, 12 | visible: PropTypes.bool.isRequired, 13 | } 14 | 15 | class PickerAddress extends React.Component { 16 | constructor(props) { 17 | super(); 18 | this.props = props; 19 | this.address = []; 20 | } 21 | 22 | initDefaultData () { 23 | this.data = { 24 | provins: { 25 | list: provins, 26 | defaultValue: this.props.defaultValue[0], 27 | displayValue (name) { 28 | return name; 29 | } 30 | }, 31 | citys: { 32 | list: citys[this.props.defaultValue[0]], 33 | defaultValue: this.props.defaultValue[1], 34 | displayValue (name) { 35 | return name; 36 | } 37 | }, 38 | areas: { 39 | list: areas[this.props.defaultValue[1]], 40 | defaultValue: this.props.defaultValue[2], 41 | displayValue (name) { 42 | return name; 43 | } 44 | } 45 | } 46 | } 47 | 48 | handleChangeProvin (provin) { 49 | this.data.provins = { 50 | list: provins, 51 | defaultValue: provin, 52 | }; 53 | this.data.citys = { 54 | list: citys[provin], 55 | defaultValue: citys[provin][0], 56 | }; 57 | this.data.areas = { 58 | list: areas[citys[provin][0]], 59 | defaultValue: areas[citys[provin][0]][0], 60 | }, 61 | this.address = []; 62 | this.address.push(provin); 63 | this.address.push(citys[provin][0]); 64 | this.address.push(areas[citys[provin][0]][0]); 65 | this.props.onChange(this.address); 66 | } 67 | 68 | handleChangeCity(city) { 69 | this.address[1] = city; 70 | this.address[2] = areas[city][0]; 71 | this.data.areas = { 72 | list: areas[city], 73 | defaultValue: areas[city][0], 74 | }; 75 | this.props.onChange(this.address); 76 | } 77 | 78 | handleChangeArea(area) { 79 | this.address[2] = area; 80 | this.props.onChange(this.address); 81 | } 82 | 83 | handleClose () { 84 | this.props.onConfirm(this.address) 85 | } 86 | 87 | handleCancel () { 88 | this.props.onCancel() 89 | } 90 | 91 | render () { 92 | this.initDefaultData(); 93 | return
94 | 98 | 102 | 106 | 110 | 111 |
112 | } 113 | } 114 | 115 | PickerAddress.propTypes = propTypes; 116 | 117 | export default PickerAddress; 118 | -------------------------------------------------------------------------------- /src/components-ext/picker-address/index.scss: -------------------------------------------------------------------------------- 1 | .ui-picker-address { 2 | 3 | .ui-picker-wrapper { 4 | width: 33%; 5 | float: left; 6 | } 7 | 8 | .ui-picker-wrapper:nth-child(2){ 9 | width: 34%; 10 | } 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | 2 | export { default as Picker } from './picker'; 3 | 4 | export { default as Popup } from './popup'; 5 | 6 | export { default as BaseModal } from './modal/BaseModal'; 7 | -------------------------------------------------------------------------------- /src/components/modal/BaseModal.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { CSSTransition } from 'react-transition-group'; 4 | import PropTypes from 'prop-types'; 5 | 6 | const propTypes = { 7 | visible: PropTypes.bool.isRequired, 8 | onCancel: PropTypes.func, 9 | } 10 | 11 | class BaseModal extends React.Component { 12 | constructor() { 13 | super(); 14 | } 15 | 16 | componentDidUpdate () { 17 | if (this.refs.modalOverlay && !this.refs.modalOverlay.onclick) { 18 | 19 | // 点击阴影背景时cancel() popup 20 | this.refs.modalOverlay.onclick = (e) => { 21 | e.stopPropagation(); 22 | this.props.onCancel && this.props.onCancel(); 23 | } 24 | 25 | // 点击modal阻止默认行为 26 | // 原理:react event listener中无法阻止原生事件,所以用原生事件来替代react事件 27 | this.refs.modal.onclick = (e) => e.stopPropagation(); 28 | } 29 | } 30 | 31 | render () { 32 | let modal = ; 33 | if (this.props.visible) { 34 | modal = ( 35 |
{ this.modalOverlay = modalOverlay;}}> 37 |
{ this.modal = modal;}}> 38 | {this.props.children} 39 |
40 |
41 | ); 42 | } 43 | return ( 44 | 45 | {modal} 46 | 47 | ); 48 | } 49 | } 50 | 51 | BaseModal.propTypes = propTypes; 52 | 53 | export default BaseModal; 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/components/modal/BaseModal.scss: -------------------------------------------------------------------------------- 1 | .modal-overlay { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | bottom:0; 6 | z-index: 1000; 7 | background-color:rgba(11,11,11,0.4); 8 | width: 100%; 9 | 10 | .modal { 11 | position: fixed; 12 | top: calc(100% - 260px); 13 | left: 0; 14 | bottom: 0; 15 | right: 0; 16 | z-index: 1001; 17 | background-color: #fff; 18 | width: 100%; 19 | height: 260px; 20 | } 21 | } 22 | 23 | .modal-transition-enter { 24 | @include fadeIn; 25 | } 26 | 27 | .modal-transition-leave { 28 | @include fadeOut; 29 | } 30 | 31 | .modal-transition-enter .modal { 32 | @include transitionBottomToUpFn('260',calc(100% - 260px)); 33 | } 34 | 35 | .modal-transition-leave .modal { 36 | @include transitionUpToBottomFn('260',calc(100% - 260px)); 37 | } 38 | -------------------------------------------------------------------------------- /src/components/picker/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springalskey/picker/e6acafcff177a23f49c729f27de867ddd8dc4932/src/components/picker/README.md -------------------------------------------------------------------------------- /src/components/picker/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import PropTypes from 'prop-types'; 4 | import _ from 'lodash'; 5 | 6 | const getIndex = (list, item) => { 7 | if (list && list.length < 1) { 8 | return 0; 9 | } 10 | let index1 = _.findIndex(list, item); 11 | let index2 = list.indexOf(item); 12 | let index = Math.max(index1, index2); 13 | if (index < 0) { 14 | throw new Error('list数组中不存在defaultValue'); 15 | } 16 | return index; 17 | } 18 | 19 | class Picker extends React.Component { 20 | constructor(props) { 21 | super(); 22 | this.props = props; 23 | this.startY = 0; 24 | this.endY = 0; 25 | //当前拖动的Y坐标 26 | this.currentY = 0; 27 | this.itemHeight = 36; 28 | this.selectedIndex = this.getInitialIndex(); 29 | this.state = {style: {}}; 30 | this._defaultValue = null; 31 | } 32 | 33 | // 初始化获得selectedIndex 34 | getInitialIndex() { 35 | let index = getIndex( 36 | this.props.data.list, 37 | this.props.data.defaultValue 38 | ); 39 | if (!this.props.data.defaultValue && this.props.data.list.length > 3) { 40 | index = Math.floor(this.props.data.list.length / 2); 41 | } 42 | return index; 43 | } 44 | 45 | componentWillReceiveProps(nextProps) { 46 | const isEqual = _.isEqual( 47 | nextProps.data.defaultValue, 48 | this._defaultValue 49 | ); 50 | if (!isEqual) { 51 | this._defaultValue = nextProps.data.defaultValue; 52 | this.selectedIndex = this.getReceivePropsIndex(nextProps.data); 53 | if (this.selectedIndex === 0) { 54 | this.setState({ 55 | style: { 56 | transform: `translate3d(0px, ${this.itemHeight * 2}px, 0px)` 57 | } 58 | }) 59 | } 60 | } 61 | } 62 | 63 | getReceivePropsIndex (data) { 64 | if (this._defaultValue) { 65 | this.selectedIndex = getIndex( 66 | data.list, 67 | data.defaultValue 68 | ); 69 | } 70 | return this.selectedIndex; 71 | } 72 | 73 | getInitialStyle () { 74 | this.currentY = 0; 75 | if (this.selectedIndex > 2) { 76 | this.currentY = - (this.selectedIndex - 2) * this.itemHeight; 77 | } else { 78 | this.currentY = (2 - this.selectedIndex) * this.itemHeight; 79 | } 80 | return `translate3d(0px, ${ this.currentY }px, 0px)`; 81 | } 82 | 83 | handleTouchStart (e) { 84 | e.preventDefault(); 85 | if (this.props.data.list.length <= 1) { 86 | return; 87 | } 88 | this.startY = e.nativeEvent.changedTouches[0].pageY; 89 | } 90 | 91 | handleTouchEnd (e) { 92 | e.preventDefault(); 93 | if (this.props.data.list.length <= 1) { 94 | return; 95 | } 96 | this.endY = e.nativeEvent.changedTouches[0].pageY; 97 | // 实际滚动距离 98 | let v = parseInt(this.endY - this.startY); 99 | let value = v % this.itemHeight; 100 | // 计算出每次拖动的36px整倍数 101 | this.currentY += (v - value); 102 | 103 | // 正数y最大值 104 | const max1 = 2 * this.itemHeight; 105 | // 负数y最小值 106 | const max2 = (this.props.data.list.length - 3) * this.itemHeight; 107 | 108 | if (this.currentY > max1) { 109 | this.currentY = max1; 110 | } 111 | else if (this.currentY > 0 && this.currentY < max1) { 112 | this.currentY = this.currentY; 113 | } 114 | else if (this.currentY === max1) { 115 | this.currentY = this.currentY; 116 | } 117 | else if (Math.abs(this.currentY) > max2) { 118 | this.currentY = - max2; 119 | } 120 | 121 | this.countListIndex(this.currentY); 122 | 123 | this.setState({ 124 | style: { 125 | transform: `translate3d(0px, ${ this.currentY }px, 0px)` 126 | } 127 | }); 128 | } 129 | 130 | handleTouchMove (e) { 131 | e.preventDefault(); 132 | if (this.props.data.list.length <= 1) { 133 | return; 134 | } 135 | const pageY = e.nativeEvent.changedTouches[0].pageY; 136 | let value = parseInt(pageY - this.startY); 137 | const y = this.currentY + value; 138 | let style = `translate3d(0px, ${ y }px, 0px)`; 139 | this.setState({ 140 | style: { 141 | transform: style 142 | } 143 | }); 144 | } 145 | 146 | // 计算list数组索引 147 | countListIndex (pageY) { 148 | let n = pageY / this.itemHeight; 149 | n = n > 0 ? 2 - n : Math.abs(n) + 2; 150 | this.setSelectedValue(n); 151 | } 152 | 153 | // set选中值 154 | setSelectedValue (index) { 155 | const length = this.props.data.list.length; 156 | if (length === 0) { 157 | this.callback(null); 158 | return; 159 | } 160 | if (index < 0 || index > length -1) { 161 | throw new Error('滑动取值索引数值出现错误'+ index); 162 | } 163 | const value = this.props.data.list[index]; 164 | this.selectedIndex = index; 165 | 166 | this.callback(value) 167 | } 168 | 169 | // 回调 170 | callback (value) { 171 | this.props.onChange(value); 172 | } 173 | 174 | getSelectedClass (index) { 175 | if (this.selectedIndex === index) { 176 | return 'ui-picker-item-selected'; 177 | } 178 | return ''; 179 | } 180 | 181 | componentDidMount () { 182 | this.setSelectedValue(this.selectedIndex); 183 | } 184 | 185 | handleWrapperStart (e) { 186 | e.preventDefault(); 187 | } 188 | 189 | render () { 190 | const style = { 191 | transform: this.getInitialStyle() 192 | } 193 | return ( 194 |
195 |
200 | { 201 | this.props.data.list.map((data, index) => { 202 | const displayValue = this.props.data.displayValue(data); 203 | return
205 | {displayValue} 206 |
207 | }) 208 | } 209 |
210 |
211 |
212 | ) 213 | } 214 | } 215 | 216 | Picker.propTypes = { 217 | // 数据源 218 | data: PropTypes.object.isRequired, 219 | // 当停止滑动选中立即回调onchange方法 220 | onChange: PropTypes.func.isRequired, 221 | }; 222 | 223 | export default Picker; 224 | -------------------------------------------------------------------------------- /src/components/picker/index.scss: -------------------------------------------------------------------------------- 1 | $itemHeight: 36px; 2 | 3 | .ui-picker-wrapper { 4 | width: 100%; 5 | height: 180px; 6 | overflow: hidden; 7 | position: relative; 8 | pointer-events: auto; 9 | margin-top: 18px; 10 | touch-action: none; 11 | 12 | .ui-picker { 13 | width: 100%; 14 | transition: transform; 15 | transition-duration: .3s; 16 | transition-timing-function: ease-out; 17 | } 18 | 19 | .ui-picker-item { 20 | height: $itemHeight; 21 | line-height: $itemHeight; 22 | text-align: center; 23 | color: #999; 24 | font-size: 18px; 25 | white-space:nowrap; 26 | text-overflow:ellipsis; 27 | overflow:hidden; 28 | } 29 | 30 | .ui-picker-item-selected { 31 | color: #000; 32 | } 33 | 34 | .ui-picker-center { 35 | height: $itemHeight; 36 | box-sizing: border-box; 37 | position: absolute; 38 | left: 0; 39 | width: 100%; 40 | top: 50%; 41 | z-index: 100; 42 | margin-top: -18px; 43 | pointer-events: none; 44 | border-top: 1px solid #d7d7d7; 45 | border-bottom: 1px solid #d7d7d7; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/components/popup/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import PropTypes from 'prop-types'; 4 | import BaseModal from '../modal/BaseModal'; 5 | 6 | const propTypes = { 7 | visible: PropTypes.bool.isRequired, 8 | onConfirm: PropTypes.func.isRequired, 9 | onCancel: PropTypes.func.isRequired, 10 | }; 11 | 12 | class Popup extends React.Component { 13 | constructor() { 14 | super(); 15 | } 16 | 17 | handleCancel () { 18 | if (this.props.onCancel) { 19 | this.props.onCancel(); 20 | } 21 | } 22 | 23 | handleConfirm() { 24 | if (this.props.onConfirm) { 25 | this.props.onConfirm(); 26 | } 27 | } 28 | 29 | /** 30 | * 使用原生事件替代react事件 31 | * 当BaseModal modal使用原生事件来阻止冒泡时 32 | * 完成与取消按钮的react onClick会失效,所以使用原生事件而不使用react事件 33 | */ 34 | componentDidUpdate () { 35 | if (this.refs.confirmButton && 36 | !this.refs.confirmButton.onclick) { 37 | 38 | this.refs.confirmButton.onclick = (e) => { 39 | e.stopPropagation(); 40 | this.handleConfirm(); 41 | } 42 | this.refs.cancelButton.onclick =(e) => { 43 | e.stopPropagation(); 44 | this.handleCancel(); 45 | } 46 | } 47 | } 48 | 49 | render () { 50 | const isZh = !navigator.language || 51 | navigator.language.toLowerCase() === 'zh-cn' || 52 | navigator.language.toLowerCase() === 'zh'; 53 | let text1 = !isZh ? 'Cancel' : '取消'; 54 | let text2 = !isZh ? 'Finish' : '完成'; 55 | return ( 56 | 59 |
60 | {text1} 61 | {text2} 62 |
63 |
64 | {this.props.children} 65 |
66 |
67 | ) 68 | } 69 | } 70 | 71 | Popup.propTypes = propTypes; 72 | 73 | export default Popup; 74 | -------------------------------------------------------------------------------- /src/components/popup/index.scss: -------------------------------------------------------------------------------- 1 | 2 | .ui-popup-title { 3 | height: 44px; 4 | font-size: 17px; 5 | background: #ccc; 6 | padding: 0 10px; 7 | line-height: 44px; 8 | 9 | > span:first-child { 10 | display: inline-block; 11 | float: left; 12 | color: #007aff; 13 | } 14 | 15 | > span:last-child { 16 | display: inline-block; 17 | float: right; 18 | color: #007aff; 19 | } 20 | } 21 | 22 | .ui-popup-content { 23 | height: 216px; 24 | width: 100%; 25 | overflow: hidden; 26 | -webkit-overflow-scrolling : touch; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/components/scss/animation.scss: -------------------------------------------------------------------------------- 1 | @mixin commonAnimation { 2 | animation-duration: 0.24s; 3 | -webkit-animation-duration: 0.24s; 4 | animation-fill-mode: both; 5 | -webkit-animation-fill-mode: both; 6 | animation-timing-function: ease-in-out; 7 | -webkit-animation-timing-function: ease-in-out; 8 | } 9 | 10 | //////////fadeIn//////////// 11 | 12 | @keyframes fadeIn { 13 | 0% { 14 | opacity: 0; 15 | } 16 | 100% { 17 | opacity: 1; 18 | } 19 | } 20 | @-webkit-keyframes fadeIn { 21 | 0% { 22 | opacity: 0; 23 | } 24 | 100% { 25 | opacity: 1; 26 | } 27 | } 28 | @mixin fadeIn { 29 | animation-name: fadeIn; 30 | -webkit-animation-name: fadeIn; 31 | @include commonAnimation; 32 | } 33 | 34 | .fadeIn { 35 | @include fadeIn; 36 | } 37 | 38 | //////////fadeOut//////////// 39 | 40 | @keyframes fadeOut { 41 | 0% { 42 | opacity: 1; 43 | } 44 | 100% { 45 | opacity: 0; 46 | } 47 | } 48 | @-webkit-keyframes fadeOut { 49 | 0% { 50 | opacity: 1; 51 | } 52 | 100% { 53 | opacity: 0; 54 | } 55 | } 56 | @mixin fadeOut { 57 | animation-name: fadeOut; 58 | -webkit-animation-name: fadeOut; 59 | @include commonAnimation; 60 | } 61 | 62 | .fadeOut { 63 | @include fadeOut; 64 | } 65 | 66 | //////////transitionBottomToUp//////////// 67 | 68 | @mixin keyframes ($name,$height) { 69 | @keyframes transitionBottomToUp-#{$name} { 70 | 0% { 71 | -webkit-transform: translate3d(0, 100%, 0); 72 | transform: translate3d(0, 100%, 0); 73 | } 74 | 100% { 75 | -webkit-transform: translate3d(0, $height, 0); 76 | transform: translate3d(0, $height, 0); 77 | } 78 | } 79 | @-webkit-keyframes transitionBottomToUp-#{$name} { 80 | 0% { 81 | -webkit-transform: translate3d(0, 100%, 0); 82 | transform: translate3d(0, 100%, 0); 83 | } 84 | 100% { 85 | -webkit-transform: translate3d(0, $height, 0); 86 | transform: translate3d(0, $height, 0); 87 | } 88 | } 89 | } 90 | 91 | @mixin transitionBottomToUp($name) { 92 | -webkit-animation-name: transitionBottomToUp-#{$name}; 93 | animation-name: transitionBottomToUp-#{$name}; 94 | @include commonAnimation; 95 | animation-duration: 0.2s; 96 | -webkit-animation-duration: 0.2s; 97 | } 98 | 99 | // 由下至上的动画,$name:动画名称后缀;$to:从底部到to位置的过度 100 | @mixin transitionBottomToUpFn ($name, $to) { 101 | @include transitionBottomToUp($name); 102 | @include keyframes ($name,$to); 103 | } 104 | 105 | //////////transitionUpToBottom//////////// 106 | 107 | @mixin keyframesUpToBottom ($name,$height) { 108 | @keyframes transitionUpToBottom-#{$name} { 109 | 0% { 110 | top: $height; 111 | -webkit-transform: translate3d(0, $height, 0); 112 | transform: translate3d(0, $height, 0); 113 | } 114 | 100% { 115 | top: 100%; 116 | -webkit-transform: translate3d(0, 100%, 0); 117 | transform: translate3d(0, 100%, 0); 118 | } 119 | } 120 | @-webkit-keyframes transitionUpToBottom-#{$name} { 121 | 0% { 122 | top: $height; 123 | -webkit-transform: translate3d(0, $height, 0); 124 | transform: translate3d(0, $height, 0); 125 | } 126 | 100% { 127 | top: 100%; 128 | -webkit-transform: translate3d(0, 100%, 0); 129 | transform: translate3d(0, 100%, 0); 130 | } 131 | } 132 | } 133 | 134 | @mixin transitionUpToBottom($name) { 135 | animation-name: transitionUpToBottom-#{$name}; 136 | -webkit-animation-name: transitionUpToBottom-#{$name}; 137 | @include commonAnimation; 138 | animation-duration: 0.2s; 139 | -webkit-animation-duration: 0.2s; 140 | } 141 | 142 | // 由上至下的动画,$name:动画名称后缀;$to:从to位置到底部的过度 143 | @mixin transitionUpToBottomFn ($name, $to) { 144 | @include transitionUpToBottom($name); 145 | @include keyframesUpToBottom ($name,$to); 146 | } 147 | 148 | -------------------------------------------------------------------------------- /src/components/scss/index.scss: -------------------------------------------------------------------------------- 1 | @import './animation.scss'; 2 | @import '../modal/BaseModal.scss'; 3 | @import '../picker/index.scss'; 4 | @import '../popup/index.scss'; 5 | -------------------------------------------------------------------------------- /src/container/home/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Link} from 'react-router-dom'; 3 | 4 | export default class Home extends React.Component { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | render() { 10 | return ( 11 |
12 |
13 |
14 | 15 | picker demo 16 | 17 |
18 |
19 |
20 | ) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/container/home/index.scss: -------------------------------------------------------------------------------- 1 | .home { 2 | margin-top: 15px; 3 | a{ 4 | display: block; 5 | background-color: #eaecec; 6 | width: 100%; 7 | height: 50px; 8 | color: black; 9 | font-weight: bold; 10 | font-size: 15px; 11 | 12 | margin-bottom: 5px; 13 | 14 | .title { 15 | padding: 15px; 16 | float: left; 17 | } 18 | } 19 | a:hover, a:active { 20 | background-color: #c9cece; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/container/layout.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import {Link} from 'react-router'; 4 | 5 | export default class App extends React.Component { 6 | constructor() { 7 | super(); 8 | } 9 | 10 | render() { 11 | return ( 12 |
13 | {this.props.children} 14 |
15 | ) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/container/picker/index.scss: -------------------------------------------------------------------------------- 1 | .picker-demo { 2 | text-align: center; 3 | 4 | .button-wrap { 5 | margin: 10px; 6 | } 7 | 8 | .item { 9 | width: 100%; 10 | height: 44px; 11 | line-height: 44px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/container/picker/picker-demo.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Picker, Popup} from '../../components'; 3 | import { PickerAddress } from '../../components-ext'; 4 | import './index.scss'; 5 | 6 | export default class PickerDemo extends React.Component { 7 | 8 | constructor() { 9 | super(); 10 | 11 | this.defaultAddress = ['湖南省','长沙市','开福区']; 12 | this.state = { 13 | userPickerVisible: false, 14 | addressPickerVisible: false, 15 | defaultValue: {name: 'Lincal', value: 5}, 16 | address: this.defaultAddress, 17 | }; 18 | 19 | this.userData = { 20 | list: [ 21 | {name: '杜保坤', value: 0}, 22 | {name: '况宏瑞', value: 1}, 23 | {name: '盘维', value: 2}, 24 | {name: '杨泉', value: 3}, 25 | {name: '福娃', value: 4}, 26 | {name: 'Lincal', value: 5}, 27 | {name: '记忆残骸', value: 6}, 28 | {name: 'Raoh', value: 7}, 29 | {name: '铁甲飞龙', value: 8}, 30 | {name: '吴泽兵', value: 9}, 31 | {name: '邱福龙', value: 10}, 32 | {name: '小泥巴', value: 11}, 33 | ], 34 | defaultValue: this.state.defaultValue, 35 | displayValue (item) { 36 | return item.name; 37 | } 38 | }; 39 | 40 | } 41 | 42 | // user选择 43 | showUserPicker (e) { 44 | e.nativeEvent.stopImmediatePropagation(); 45 | this.setState({userPickerVisible: true}); 46 | } 47 | 48 | handleChangeUser (data) { 49 | data = data || {} 50 | this.userData.defaultValue = data; 51 | this.setState({defaultValue: data}); 52 | } 53 | 54 | closeUserPicker () { 55 | this.setState({userPickerVisible: false}); 56 | } 57 | 58 | cancelUserPicker () { 59 | this.userData.defaultValue = {}; 60 | this.setState({ 61 | userPickerVisible: false, 62 | defaultValue: {} 63 | }); 64 | } 65 | 66 | // 地址选择 67 | showAddressPicker (e) { 68 | e.nativeEvent.stopImmediatePropagation(); 69 | this.setState({addressPickerVisible: true}); 70 | } 71 | 72 | handleChangeAddress (address) { 73 | this.setState({address: address}); 74 | } 75 | 76 | closeAddressPicker (address) { 77 | this.setState({ 78 | address: address, 79 | addressPickerVisible: false, 80 | }); 81 | } 82 | 83 | cancelAddressPicker () { 84 | this.setState({ 85 | address: this.defaultAddress, 86 | addressPickerVisible: false, 87 | }); 88 | } 89 | 90 | render() { 91 | return ( 92 |
93 |
94 | { this.state.defaultValue.name } 95 |
96 |
97 | 101 | 105 | 106 |
107 | 108 | 114 | 115 | 116 |
117 | 123 |
124 | 125 |
126 | { this.state.address } 127 |
128 | 129 |
130 | 136 |
137 | 138 |
139 | ) 140 | } 141 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | REACT PICKER 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill'; 2 | import React from 'react'; 3 | import {render} from 'react-dom'; 4 | import {BrowserRouter,HashRouter,Route} from 'react-router-dom'; 5 | 6 | import Layout from './container/layout'; 7 | import HomeRoute from './container/home'; 8 | import PickerRoute from './container/picker/picker-demo'; 9 | 10 | import './scss/index.scss'; 11 | 12 | 13 | render( 14 | 15 | 16 | 17 | 18 | 19 | , 20 | document.getElementById('app') 21 | ); 22 | 23 | -------------------------------------------------------------------------------- /src/scss/button.scss: -------------------------------------------------------------------------------- 1 | 2 | $height: 30px; 3 | 4 | .button { 5 | border-style: none; 6 | width: auto; 7 | overflow: visible; 8 | text-align: center; 9 | outline: none; 10 | background-color: #eee; 11 | border-radius: 5px; 12 | margin: auto; 13 | } 14 | 15 | .button-primary { 16 | width: 200px; 17 | height: $height; 18 | color: #fff; 19 | background-color: #5bc0de; 20 | border-color: #46b8da; 21 | } 22 | 23 | .button-large { 24 | width: 80%; 25 | height: $height; 26 | color: #fff; 27 | background-color: #f0ad4e; 28 | border-color: #eea236; 29 | } 30 | 31 | .button-small { 32 | width: 66px; 33 | height: $height; 34 | color: #333; 35 | background-color: #fff; 36 | border-color: #ccc; 37 | } 38 | 39 | .btn { 40 | display: inline-block; 41 | margin-bottom: 0; 42 | font-size: 14px; 43 | text-align: center; 44 | white-space: nowrap; 45 | vertical-align: middle; 46 | -ms-touch-action: manipulation; 47 | touch-action: manipulation; 48 | cursor: pointer; 49 | -webkit-user-select: none; 50 | -moz-user-select: none; 51 | -ms-user-select: none; 52 | user-select: none; 53 | background-image: none; 54 | border: 1px solid transparent; 55 | border-radius: 4px; 56 | font-family: inherit; 57 | text-transform: none; 58 | outline: none; 59 | } 60 | 61 | .btn:focus, .btn:hover { 62 | color: #fff; 63 | background-color: #31b0d5; 64 | border-color: #269abc; 65 | } 66 | -------------------------------------------------------------------------------- /src/scss/index.scss: -------------------------------------------------------------------------------- 1 | @import "reset.scss"; 2 | @import "list.scss"; 3 | @import "button.scss"; 4 | @import "../components/scss/index.scss"; -------------------------------------------------------------------------------- /src/scss/list.scss: -------------------------------------------------------------------------------- 1 | 2 | //
3 | //
4 | // 5 | //
6 | //
7 | 8 | $height: 56px; 9 | $input-color: #000; 10 | $border-color: #000; 11 | 12 | .list { 13 | width: 100%; 14 | .item { 15 | height: $height; 16 | line-height: $height; 17 | margin: 0 10px; 18 | border-bottom: 1px solid $border-color; 19 | box-sizing: border-box; 20 | } 21 | 22 | .item-label { 23 | width: 100%; 24 | height: 100%; 25 | display: inline-block; 26 | padding-right: 20px; 27 | text-overflow: ellipsis; 28 | white-space: nowrap; 29 | overflow: hidden; 30 | box-sizing: border-box; 31 | color: $input-color; 32 | position: relative; 33 | 34 | &:after { 35 | display: block; 36 | width: 8px; 37 | height: 8px; 38 | border: 1px solid #000; 39 | border-left: 0; 40 | border-top: 0; 41 | transform: rotate(315deg); 42 | content: ''; 43 | position: absolute; 44 | right: 8px; 45 | top: 23px; 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/scss/reset.scss: -------------------------------------------------------------------------------- 1 | .clearfix:after {content: "."; display: block; height: 0; clear: both; visibility: hidden;} 2 | .clearfix {*zoom:1} 3 | ul, ol,li{list-style:none;} 4 | img, input{border: 0; outline: none;} 5 | body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { margin:0; padding:0; } 6 | h1, h2, h3, h4, h5, h6{ font-size:100%; } 7 | table { border-collapse:collapse; border-spacing:0; } 8 | a{ text-decoration: none; outline: none;} 9 | *{ -webkit-tap-highlight-color: rgba(0,0,0,0);-webkit-tap-highlight-color: transparent;} 10 | 11 | html,body{ 12 | width: 100%; 13 | height: 100%; 14 | margin: 0; 15 | padding: 0; 16 | overflow: auto; 17 | font-family: PingFangSC-Regular, Helvetica, sans-serif; 18 | font-size: 14px; 19 | color: #000; 20 | } 21 | 22 | input::-webkit-input-placeholder, 23 | textarea::-webkit-input-placeholder { 24 | color: #cccccc !important; 25 | font-size: 14px; 26 | } 27 | 28 | input[readonly] { 29 | background-color: transparent !important; 30 | } 31 | 32 | select { 33 | font-size: 16px; 34 | color: #666; 35 | border: none; 36 | padding: none; 37 | appearance: none; 38 | background-color: transparent; 39 | } 40 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 4 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 5 | 6 | var isProd = process.env.NODE_ENV === 'production'; 7 | var cssLoader = isProd ? ExtractTextPlugin.extract('css-loader!sass-loader') : ['style-loader', 'css-loader', 'sass-loader']; 8 | 9 | 10 | var path = require('path'); 11 | var https = require('https'); 12 | var ip = require('ip'); 13 | 14 | var port = 9998; 15 | var url = 'http://'+ip.address()+':' + port + '/'; 16 | 17 | var config = { 18 | devtool: '#eval-source-map', 19 | entry: { 20 | app: './src/main.js', 21 | }, 22 | output: { 23 | path: path.join(__dirname, './build'), 24 | filename: '[name].[hash:7].js', 25 | publicPath: isProd ? '' : url, 26 | }, 27 | 28 | resolve: { 29 | extensions: ['*', '.js', '.jsx'] 30 | }, 31 | 32 | plugins: [ 33 | new HtmlWebpackPlugin({ 34 | template: 'src/index.html', 35 | filename: 'index.html', 36 | }) 37 | ], 38 | 39 | module: { 40 | loaders: [{ 41 | test: /\.jsx?$/, 42 | loader: 'babel-loader', 43 | exclude: /node_modules/ 44 | }, 45 | { test: /\.(scss|css)$/, loader: cssLoader }, 46 | { 47 | test: /\.(png|jpg|gif|ico)$/, 48 | loader: 'url-loader?limit=8192&name=assets/[name].[ext]' 49 | }] 50 | }, 51 | 52 | devServer: { 53 | port: port, 54 | host: ip.address(), 55 | contentBase: "./src", 56 | historyApiFallback: true, 57 | compress: true, 58 | stats: 'minimal', 59 | } 60 | }; 61 | 62 | if (isProd) { 63 | config.devtool = '#source-map'; 64 | config.plugins.push( 65 | 66 | new ExtractTextPlugin('app.[hash:8].css', {allChunks: true}) 67 | ); 68 | } 69 | 70 | module.exports = config; 71 | --------------------------------------------------------------------------------