四级地址插件升级改造(京东商城地址选择插件)city-picker

最近公司做的项目要和京东的数据做对接,所以要做个类似京东商品的详情页。页面的数据,是可以从京东接口获取到的,但是地址插件选择的效果需要自己实现。前端的同事在之前的项目中,已经选择了一款地址插件(city-picker.js),但是这款插件最多只支持三级地址,而且最主要的是这插件的地址数据来源,是写死在一个json文件中的,意思就是说,在使用这个插件的时候页面要一次性的把所有的地址数据都加载出来,这在pc端一般倒还可以承受,但是到了,移动端,随便一个手机就会卡死,浏览器直接崩溃。

经过在网上的各种查找,和研究,发现一个博客,

对city-picker这个插件进行了扩展,扩展成了支持四级地址的插件了。这正是我想要的,因为京东给过来的地址数据就是4级的。正好可以使用。然后就拿过来直接用了。

很强大,完美的满足了,我的需求。但是这个大神的博客只是将三级地址改造成了四级地址,没有解决,动态加载数据的问题,就是说用这个四级地址插件的时候,还是要把京东的地址库数据转成json文件一次性加载到页面。这样的话在移动端浏览时还是会把浏览器搞崩。

好了,说了这么多铺垫的废话,就是为了引出,我对这个四级地址插件的改造。

直接代码

1 /*! 2 * CityPicker v@VERSION 3 * https://github.com/tshi0912/citypicker 4 * 5 * Copyright (c) 2015-@YEAR Tao Shi 6 * Released under the MIT license 7 * 8 * Date: @DATE 9 */ 10 11 12 ChineseDistricts={ 13 "86": { 14 "中国": [ 15 { 16 "address": "北京", 17 "code": "1" 18 }, 19 { 20 "address": "上海", 21 "code": "2" 22 }, 23 { 24 "address": "天津", 25 "code": "3" 26 }, 27 { 28 "address": "重庆", 29 "code": "4" 30 }, 31 { 32 "address": "河北", 33 "code": "5" 34 }, 35 { 36 "address": "山西", 37 "code": "6" 38 }, 39 { 40 "address": "河南", 41 "code": "7" 42 }, 43 { 44 "address": "辽宁", 45 "code": "8" 46 }, 47 { 48 "address": "吉林", 49 "code": "9" 50 }, 51 { 52 "address": "黑龙江", 53 "code": "10" 54 }, 55 { 56 "address": "内蒙古", 57 "code": "11" 58 }, 59 { 60 "address": "江苏", 61 "code": "12" 62 }, 63 { 64 "address": "山东", 65 "code": "13" 66 }, 67 { 68 "address": "安徽", 69 "code": "14" 70 }, 71 { 72 "address": "浙江", 73 "code": "15" 74 }, 75 { 76 "address": "福建", 77 "code": "16" 78 }, 79 { 80 "address": "湖北", 81 "code": "17" 82 }, 83 { 84 "address": "湖南", 85 "code": "18" 86 }, 87 { 88 "address": "广东", 89 "code": "19" 90 }, 91 { 92 "address": "广西", 93 "code": "20" 94 }, 95 { 96 "address": "江西", 97 "code": "21" 98 }, 99 { 100 "address": "四川", 101 "code": "22" 102 }, 103 { 104 "address": "海南", 105 "code": "23" 106 }, 107 { 108 "address": "贵州", 109 "code": "24" 110 }, 111 { 112 "address": "云南", 113 "code": "25" 114 }, 115 { 116 "address": "西藏", 117 "code": "26" 118 }, 119 { 120 "address": "陕西", 121 "code": "27" 122 }, 123 { 124 "address": "甘肃", 125 "code": "28" 126 }, 127 { 128 "address": "青海", 129 "code": "29" 130 }, 131 { 132 "address": "宁夏", 133 "code": "30" 134 }, 135 { 136 "address": "新疆", 137 "code": "31" 138 }, 139 { 140 "address": "台湾", 141 "code": "32" 142 }, 143 { 144 "address": "钓鱼岛", 145 "code": "84" 146 }, 147 { 148 "address": "港澳", 149 "code": "52993" 150 } 151 ] 152 } 153 }; 154 155 (function (factory) { 156 if (typeof define === 'function' && define.amd) { 157 // AMD. Register as anonymous module. 158 define(['jquery', 'ChineseDistricts'], factory); 159 } else if (typeof exports === 'object') { 160 // Node / CommonJS 161 factory(require('jquery'), require('ChineseDistricts')); 162 } else { 163 // Browser globals. 164 factory(jQuery, ChineseDistricts); 165 } 166 })(function ($, ChineseDistricts) { 167 168 'use strict'; 169 if (typeof ChineseDistricts === 'undefined') { 170 throw new Error('The file "city-picker.data.js" must be included first!'); 171 } 172 var NAMESPACE = 'citypicker'; 173 var EVENT_CHANGE = 'change.' + NAMESPACE; 174 var PROVINCE = 'province'; 175 var CITY = 'city'; 176 var DISTRICT = 'district'; 177 var COUNTY = 'county'; 178 179 function CityPicker(element, options) { 180 this.$element = $(element); 181 this.$dropdown = null; 182 this.options = $.extend({}, CityPicker.DEFAULTS, $.isPlainObject(options) && options); 183 this.active = false; 184 this.dems = []; 185 this.needBlur = false; 186 this.init(); 187 } 188 189 CityPicker.prototype = { 190 constructor: CityPicker, 191 192 init: function () { 193 194 this.defineDems(); 195 196 this.render(); 197 198 this.bind(); 199 200 this.active = true; 201 }, 202 //界面显示处理 203 render: function () { 204 var p = this.getPosition(), 205 placeholder = this.$element.attr('placeholder') || this.options.placeholder, 206 textspan = '<spancolor: #008080">207 this.getWidthStyle(p.width) + 'height:' + 208 p.height + 'px;line-height:' + (p.height - 1) + 'px;">' + 209 (placeholder ? '<span>' + placeholder + '</span>' : '') + 210 '<span></span><div></div>' + '</span>', 211 212 dropdown = '<divcolor: #008080">213 this.getWidthStyle(p.width, true) + '">' + 214 '<div>' + 215 '<div>' + 216 '<a data-count="province">省份</a>' + 217 (this.includeDem('city') ? '<a data-count="city">城市</a>' : '') + 218 (this.includeDem('district') ? '<a data-count="district">区县</a>' : '') + 219 (this.includeDem('county') ? '<a data-count="county">乡镇</a>' : '') + 220 '</div>' + 221 '<div>' + 222 '<div data-count="province"></div>' + 223 (this.includeDem('city') ? '<div data-count="city"></div>' : '') + 224 (this.includeDem('district') ? '<div data-count="district"></div>' : '') + 225 (this.includeDem('county') ? '<div data-count="county"></div>' : '') + 226 '</div></div>'; 227 228 this.$element.addClass('city-picker-input'); 229 this.$textspan = $(textspan).insertAfter(this.$element); 230 this.$dropdown = $(dropdown).insertAfter(this.$textspan); 231 var $select = this.$dropdown.find('.city-select'); 232 233 // setup this.$province, this.$city and/or this.$district object 234 $.each(this.dems, $.proxy(function (i, type) { 235 this['$' + type] = $select.filter('.' + type + ''); 236 }, this)); 237 238 this.refresh(); 239 }, 240 241 refresh: function (force) { 242 // clean the data-item for each $select 243 var $select = this.$dropdown.find('.city-select'); 244 $select.data('item', null); 245 // parse value from value of the target $element 246 var val = this.$element.val() || ''; 247 val = val.split('http://www.likecs.com/'); 248 $.each(this.dems, $.proxy(function (i, type) {//遍历dems 249 if (val[i] && i < val.length) { 250 this.options[type] = val[i];//把当前显示值赋值给options 251 } else if (force) { 252 this.options[type] = ''; 253 } 254 this.output(type);//输出下拉框显示数据 255 }, this)); 256 this.tab(PROVINCE); 257 this.feedText();//界面显示选择的内容 258 this.feedVal();//input标签value赋值 259 }, 260 //dems赋值 261 defineDems: function () { 262 var stop = false; 263 $.each([PROVINCE, CITY, DISTRICT,COUNTY], $.proxy(function (i, type) { 264 if (!stop) { 265 this.dems.push(type); 266 } 267 if (type === this.options.level) { 268 stop = true; 269 } 270 }, this)); 271 }, 272 273 includeDem: function (type) { 274 return $.inArray(type, this.dems) !== -1; 275 }, 276 277 getPosition: function () { 278 var p, h, w, s, pw; 279 p = this.$element.position(); 280 s = this.getSize(this.$element); 281 h = s.height; 282 w = s.width; 283 if (this.options.responsive) { 284 pw = this.$element.offsetParent().width(); 285 if (pw) { 286 w = w / pw; 287 if (w > 0.99) { 288 w = 1; 289 } 290 w = w * 100 + '%'; 291 } 292 } 293 294 return { 295 top: p.top || 0, 296 left: p.left || 0, 297 height: h, 298 width: w 299 }; 300 }, 301 302 getSize: function ($dom) { 303 var $wrap, $clone, sizes; 304 if (!$dom.is(':visible')) { 305 $wrap = $("<div />").appendTo($("body")); 306 $wrap.css({ 307 "position": "absolute !important", 308 "visibility": "hidden !important", 309 "display": "block !important" 310 }); 311 312 $clone = $dom.clone().appendTo($wrap); 313 314 sizes = { 315 width: $clone.outerWidth(), 316 height: $clone.outerHeight() 317 }; 318 319 $wrap.remove(); 320 } else { 321 sizes = { 322 width: $dom.outerWidth(), 323 height: $dom.outerHeight() 324 }; 325 } 326 327 return sizes; 328 }, 329 330 getWidthStyle: function (w, dropdown) { 331 if (this.options.responsive && !$.isNumeric(w)) { 332 return 'width:' + w + ';'; 333 } else { 334 return 'width:' + (dropdown ? Math.max(320, w) : w) + 'px;'; 335 } 336 }, 337 //绑定事件 338 bind: function () { 339 var $this = this; 340 $(document).on('click', (this._mouteclick = function (e) { 341 var $target = $(e.target); 342 var $dropdown, $span, $input; 343 if ($target.is('.city-picker-span')) { 344 $span = $target; 345 } else if ($target.is('.city-picker-span *')) { 346 $span = $target.parents('.city-picker-span'); 347 } 348 if ($target.is('.city-picker-input')) { 349 $input = $target; 350 } 351 if ($target.is('.city-picker-dropdown')) { 352 $dropdown = $target; 353 } else if ($target.is('.city-picker-dropdown *')) { 354 $dropdown = $target.parents('.city-picker-dropdown'); 355 } 356 if ((!$input && !$span && !$dropdown) || 357 ($span && $span.get(0) !== $this.$textspan.get(0)) || 358 ($input && $input.get(0) !== $this.$element.get(0)) || 359 ($dropdown && $dropdown.get(0) !== $this.$dropdown.get(0))) { 360 $this.close(true); 361 } 362 })); 363 this.$element.on('change', (this._changeElement = $.proxy(function () { 364 this.close(true); 365 this.refresh(true); 366 }, this))).on('focus', (this._focusElement = $.proxy(function () { 367 this.needBlur = true; 368 this.open(); 369 }, this))).on('blur', (this._blurElement = $.proxy(function () { 370 if (this.needBlur) { 371 this.needBlur = false; 372 this.close(true); 373 } 374 }, this))); 375 this.$textspan.on('click', function (e) { 376 var $target = $(e.target), type; 377 $this.needBlur = false; 378 if ($target.is('.select-item')) { 379 type = $target.data('count'); 380 $this.open(type); 381 } else { 382 if ($this.$dropdown.is(':visible')) { 383 $this.close(); 384 } else { 385 $this.open(); 386 } 387 } 388 }).on('mousedown', function () { 389 $this.needBlur = false; 390 }); 391 this.$dropdown.on('click', '.city-select a', function () { 392 var $select = $(this).parents('.city-select'); 393 var $active = $select.find('a.active'); 394 var last = $select.next().length === 0; 395 $active.removeClass('active'); 396 $(this).addClass('active'); 397 if ($active.data('code') !== $(this).data('code')) { 398 $select.data('item', { 399 address: $(this).attr('title'), code: $(this).data('code') 400 }); 401 $(this).trigger(EVENT_CHANGE); 402 $this.feedText(); 403 $this.feedVal(true); 404 if (last) { 405 $this.close(); 406 } 407 } 408 }).on('click', '.city-select-tab a', function () { 409 if (!$(this).hasClass('active')) { 410 var type = $(this).data('count'); 411 $this.tab(type); 412 } 413 }).on('mousedown', function () { 414 $this.needBlur = false; 415 }); 416 if (this.$province) { 417 this.$province.on(EVENT_CHANGE, (this._changeProvince = $.proxy(function () { 418 if(this.output(CITY)){//判断下一个tab是否有数据,没有则关闭下拉 419 $this.close(); 420 return; 421 }; 422 this.output(CITY); 423 this.output(DISTRICT); 424 this.output(COUNTY); 425 this.tab(CITY); 426 }, this))); 427 } 428 if (this.$city) { 429 this.$city.on(EVENT_CHANGE, (this._changeCity = $.proxy(function () { 430 if(this.output(DISTRICT)){ 431 $this.close(); 432 return; 433 }; 434 this.output(COUNTY); 435 this.tab(DISTRICT); 436 }, this))); 437 } 438 439 if (this.$district) { 440 this.$district.on(EVENT_CHANGE, (this._changeDistrict = $.proxy(function () { 441 if(this.output(COUNTY)){ 442 $this.close(); 443 return; 444 }; 445 this.tab(COUNTY); 446 }, this))); 447 } 448 }, 449 //显示下拉 450 open: function (type) { 451 type = type || PROVINCE; 452 this.$dropdown.show(); 453 this.$textspan.addClass('open').addClass('focus'); 454 this.tab(type); 455 }, 456 //关闭下拉 457 close: function (blur) { 458 this.$dropdown.hide(); 459 this.$textspan.removeClass('open'); 460 if (blur) { 461 this.$textspan.removeClass('focus'); 462 } 463 }, 464 //解绑事件 465 unbind: function () { 466 467 $(document).off('click', this._mouteclick); 468 469 this.$element.off('change', this._changeElement); 470 this.$element.off('focus', this._focusElement); 471 this.$element.off('blur', this._blurElement); 472 473 this.$textspan.off('click'); 474 this.$textspan.off('mousedown'); 475 476 this.$dropdown.off('click'); 477 this.$dropdown.off('mousedown'); 478 479 if (this.$province) { 480 this.$province.off(EVENT_CHANGE, this._changeProvince); 481 } 482 483 if (this.$city) { 484 this.$city.off(EVENT_CHANGE, this._changeCity); 485 } 486 487 if (this.$district) { 488 this.$district.off(EVENT_CHANGE, this._changeDistrict); 489 } 490 }, 491 //获取选择项信息 492 getText: function () { 493 var text = ''; 494 this.$dropdown.find('.city-select') 495 .each(function () { 496 var item = $(this).data('item'), 497 type = $(this).data('count'); 498 if (item) { 499 text += ($(this).hasClass('province') ? '' : 'http://www.likecs.com/') + '<span data-count="' + 500 type + '" data-code="' + item.code + '">' + item.address + '</span>'; 501 } 502 }); 503 return text; 504 }, 505 getPlaceHolder: function () { 506 return this.$element.attr('placeholder') || this.options.placeholder; 507 }, 508 //显示placeholder或者选择的区域 509 feedText: function () { 510 var text = this.getText(); 511 if (text) { 512 this.$textspan.find('>.placeholder').hide(); 513 this.$textspan.find('>.title').html(this.getText()).show(); 514 } else { 515 this.$textspan.find('>.placeholder').text(this.getPlaceHolder()).show(); 516 this.$textspan.find('>.title').html('').hide(); 517 } 518 }, 519 getCode: function (count) { 520 var obj = {}, arr = []; 521 this.$textspan.find('.select-item') 522 .each(function () { 523 var code = $(this).data('code'); 524 var count = $(this).data('count'); 525 obj[count] = code; 526 arr.push(code); 527 }); 528 return count ? obj[count] : arr.join('http://www.likecs.com/'); 529 }, 530 getVal: function () { 531 var text = ''; 532 var code=''; 533 this.$dropdown.find('.city-select') 534 .each(function () { 535 var item = $(this).data('item'); 536 if (item) { 537 text += ($(this).hasClass('province') ? '' : 'http://www.likecs.com/') + item.address; 538 code += ($(this).hasClass('province') ? '' : '_') + item.code; 539 } 540 }); 541 $("#addrValue").val(code); 542 return text; 543 }, 544 //input的value赋值 545 feedVal: function (trigger) { 546 this.$element.val(this.getVal()); 547 if(trigger) { 548 this.$element.trigger('cp:updated'); 549 } 550 }, 551 //输出数据 552 output: function (type) { 553 var $this = this; 554 var options = this.options; 555 //var placeholders = this.placeholders; 556 var $select = this['$' + type]; 557 var data = type === PROVINCE ? {} : []; 558 var item; 559 var districts; 560 var code; 561 var matched = null; 562 var value; 563 if (!$select || !$select.length) { 564 return; 565 } 566 item = $select.data('item'); 567 value = (item ? item.address : null) || options[type]; 568 code = ( 569 type === PROVINCE ? 86 : 570 type === CITY ? this.$province && this.$province.find('.active').data('code') : 571 type === DISTRICT ? this.$city && this.$city.find('.active').data('code') : 572 type === COUNTY ? this.$district && this.$district.find('.active').data('code') : code 573 ); 574 //districts = $.isNumeric(code) ? ChineseDistricts[code] : null; 575        //判断是否应该去远程加载数据 576 districts = $.isNumeric(code) ? this.remoteLoadData(type,code) : null; 577 if ($.isPlainObject(districts)) { 578 $.each(districts, function (code, address) { 579 var provs; 580 if (type === PROVINCE) { 581 provs = []; 582 for (var i = 0; i < address.length; i++) { 583 if (address[i].address === value) { 584 matched = { 585 code: address[i].code, 586 address: address[i].address 587 }; 588 } 589 provs.push({ 590 code: address[i].code, 591 address: address[i].address, 592 selected: address[i].address === value 593 }); 594 } 595 data[code] = provs; 596 } else { 597 if (address === value) { 598 matched = { 599 code: code, 600 address: address 601 }; 602 } 603 data.push({ 604 code: code, 605 address: address, 606 selected: address === value 607 }); 608 } 609 }); 610 } 611 612 $select.html(type === PROVINCE ? this.getProvinceList(data) : 613 this.getList(data, type)); 614 $select.data('item', matched);//当前tab添加item(包含选择对象的内容) 615 if(! (type === PROVINCE)){//标识:下一个选项没有数据则关闭 616 if(data.length==0){ 617 return true; 618 } 619 } 620 }, 621 //遍历省份 622 getProvinceList: function (data) { 623 var list = [], 624 $this = this, 625 simple = this.options.simple; 626 627 $.each(data, function (i, n) { 628 list.push('<dl>'); 629 list.push('<dt>' + i + '</dt><dd>'); 630 $.each(n, function (j, m) { 631 list.push( 632 '<a' + 633 ' title="' + (m.address || '') + '"' + 634 ' data-code="' + (m.code || '') + '"' + 635 'color: #008080">636 (m.selected ? ' active' : '') + 637 '">' + 638 ( simple ? $this.simplize(m.address, PROVINCE) : m.address) + 639 '</a>'); 640 }); 641 list.push('</dd></dl>'); 642 }); 643 644 return list.join(''); 645 }, 646 //遍历市或区或县 647 getList: function (data, type) { 648 var list = [], 649 $this = this, 650 simple = this.options.simple; 651 list.push('<dl><dd>'); 652 653 $.each(data, function (i, n) { 654 list.push( 655 '<a' + 656 ' title="' + (n.address || '') + '"' + 657 ' data-code="' + (n.code || '') + '"' + 658 'color: #008080">659 (n.selected ? ' active' : '') + 660 '">' + 661 ( simple ? $this.simplize(n.address, type) : n.address) + 662 '</a>'); 663 }); 664 list.push('</dd></dl>'); 665 666 return list.join(''); 667 }, 668 //简化名字 669 simplize: function (address, type) { 670 address = address || ''; 671 if (type === PROVINCE) { 672 return address.replace(/[省,市,自治区,壮族,回族,维吾尔]/g, ''); 673 } else if (type === CITY) { 674 return address.replace(/[市,地区,回族,蒙古,苗族,白族,傣族,景颇族,藏族,彝族,壮族,傈僳族,布依族,侗族]/g, '') 675 .replace('哈萨克', '').replace('自治州', '').replace(/自治县/, ''); 676 } else if (type === DISTRICT) { 677 return address.length > 2 ? address.replace(/[市,区,县,旗]/g, '') : address; 678 } 679 }, 680 //处理tab显示 681 tab: function (type) { 682 var $selects = this.$dropdown.find('.city-select'); 683 var $tabs = this.$dropdown.find('.city-select-tab > a'); 684 var $select = this['$' + type]; 685 var $tab = this.$dropdown.find('.city-select-tab > a[data-count="' + type + '"]'); 686 if ($select) { 687 $selects.hide(); 688 $select.show(); 689 $tabs.removeClass('active'); 690 $tab.addClass('active'); 691 } 692 }, 693 694 reset: function () { 695 this.$element.val(null).trigger('change'); 696 }, 697 698 destroy: function () { 699 this.unbind(); 700 this.$element.removeData(NAMESPACE).removeClass('city-picker-input'); 701 this.$textspan.remove(); 702 this.$dropdown.remove(); 703 }, 704 //远程加载数据 705 remoteLoadData: function (cityType,cityId) { 706 var resultData = {}; 707 if(PROVINCE===cityType) 708 { 709 return ChineseDistricts[cityId]; 710 } 711 $.ajax({ 712 url: "/directoryProcurement/jd/cityData/"+cityType+"http://www.likecs.com/"+cityId, 713 type: "GET", 714 dataType: "json", 715 async: false, 716 contentType: "application/json", 717 success: function (result) { 718 if(result.code=="0") 719 { 720 resultData = result.data; 721 }else 722 { 723 console.log(result.desc); 724 } 725 } 726 }); 727 return resultData; 728 } 729 }; 730 731 CityPicker.DEFAULTS = { 732 simple: false, 733 responsive: false, 734 placeholder: '请选择省/市/区/镇', 735 level: 'county', 736 province: '', 737 city: '', 738 district: '', 739 county:'' 740 }; 741 742 CityPicker.setDefaults = function (options) { 743 $.extend(CityPicker.DEFAULTS, options); 744 }; 745 746 // Save the other citypicker 747 CityPicker.other = $.fn.citypicker; 748 749 // Register as jQuery plugin 750 $.fn.citypicker = function (option) { 751 var args = [].slice.call(arguments, 1); 752 753 return this.each(function () { 754 var $this = $(this); 755 var data = $this.data(NAMESPACE); 756 var options; 757 var fn; 758 759 if (!data) { 760 if (/destroy/.test(option)) { 761 return; 762 } 763 764 options = $.extend({}, $this.data(), $.isPlainObject(option) && option); 765 $this.data(NAMESPACE, (data = new CityPicker(this, options))); 766 } 767 768 if (typeof option === 'string' && $.isFunction(fn = data[option])) { 769 fn.apply(data, args); 770 } 771 }); 772 }; 773 774 $.fn.citypicker.Constructor = CityPicker; 775 $.fn.citypicker.setDefaults = CityPicker.setDefaults; 776 777 // No conflict 778 $.fn.citypicker.noConflict = function () { 779 $.fn.citypicker = CityPicker.other; 780 return this; 781 }; 782 783 $(function () { 784 $('[data-toggle="city-picker"]').citypicker(); 785 }); 786 });

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyypyp.html