四级地址插件升级改造(京东商城地址选择插件)city-picker
Posted 纪莫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了四级地址插件升级改造(京东商城地址选择插件)city-picker相关的知识,希望对你有一定的参考价值。
最近公司做的项目要和京东的数据做对接,所以要做个类似京东商品的详情页。页面的数据,是可以从京东接口获取到的,但是地址插件选择的效果需要自己实现。前端的同事在之前的项目中,已经选择了一款地址插件(city-picker.js),但是这款插件最多只支持三级地址,而且最主要的是这插件的地址数据来源,是写死在一个json文件中的,意思就是说,在使用这个插件的时候页面要一次性的把所有的地址数据都加载出来,这在pc端一般倒还可以承受,但是到了,移动端,随便一个手机就会卡死,浏览器直接崩溃。
经过在网上的各种查找,和研究,发现一个博客,http://www.cnblogs.com/huangchanghuan/p/6681510.html
对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 = \'<span class="city-picker-span" style="\' + 207 this.getWidthStyle(p.width) + \'height:\' + 208 p.height + \'px;line-height:\' + (p.height - 1) + \'px;">\' + 209 (placeholder ? \'<span class="placeholder">\' + placeholder + \'</span>\' : \'\') + 210 \'<span class="title"></span><div class="arrow"></div>\' + \'</span>\', 211 212 dropdown = \'<div class="city-picker-dropdown" style="left:0px;top:100%;\' + 213 this.getWidthStyle(p.width, true) + \'">\' + 214 \'<div class="city-select-wrap">\' + 215 \'<div class="city-select-tab">\' + 216 \'<a class="active" 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 class="city-select-content">\' + 222 \'<div class="city-select province" data-count="province"></div>\' + 223 (this.includeDem(\'city\') ? \'<div class="city-select city" data-count="city"></div>\' : \'\') + 224 (this.includeDem(\'district\') ? \'<div class="city-select district" data-count="district"></div>\' : \'\') + 225 (this.includeDem(\'county\') ? \'<div class="city-select county" 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(\'/\'); 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\') ? \'\' : \'/\') + \'<span class="select-item" data-count="\' + ecshop二次开发功能插件计划列表