/** * cityPicker * v-1.0.0 * dataJson [Json] json数据,是html显示的列表数据 * selectpattern [Array] 用于存储的字段名和默认提示 { 字段名,默认提示 } * shorthand [Boolean] 用于城市简写功能,默认是不开启(false) * storage [Boolean] 存储的值是数字还是中文,默认是(true)数字 * linkage [Boolean] 是否联动,默认(true) * renderMode [Boolean] 是模拟的还是原生的;只在type是selector才有效,默认是(true)模拟 * code [Boolean] 是否输出城市区号值,默认(false),开启就是传字段名('code') * search [Boolean] 是否开启搜索功能,默认(true) * level [Number] 多少列 默认是一列/级 (3) * onInitialized [Attachable] 组件初始化后触发的回调函数 * onClickBefore [Attachable] 组件点击显示列表触发的回调函数(除原生select) * onForbid [Attachable] 存在class名forbid的禁止点击的回调 * choose-xx [Attachable] 点击组件选项后触发的回调函数 xx(级名称/province/city/district)是对应的级的回调 */ (function ($, window) { var $selector; var grade = ['province', 'city', 'district']; var defaults = { dataJson: null, selectpattern: [{ field: 'userProvinceId', placeholder: '请选择省份' }, { field: 'userCityId', placeholder: '请选择城市' }, { field: 'userDistrictId', placeholder: '请选择区县' } ], shorthand: false, storage: true, linkage: true, renderMode: true, code: false, search: true, level: 3, onInitialized: function () {}, onClickBefore: function () {}, onForbid: function () {} }; function Citypicker(options, selector) { this.options = $.extend({}, defaults, options); this.$selector = $selector = $(selector); this.init(); this.events(); } //功能模块函数 var effect = { montage: function (data, pid, reg) { var self = this, config = self.options, leng = data.length, html = '', code, name, reverse, storage; for (var i = 0; i < leng; i++) { if (data[i].parentId === pid) { //判断是否要输出区号 code = config.code && data[i].cityCode !== '' ? 'data-code=' + data[i].cityCode : ''; //判断是否开启了简写,是就用输出简写,否则就输出全称 name = config.shorthand ? data[i].shortName : data[i].name; //反向:判断是否开启了简写,是就用输出简写,否则就输出全称 reverse = !config.shorthand ? data[i].shortName : data[i].name; //存储的是数字还是中文 storage = config.storage ? data[i].id : name; if (config.renderMode) { //模拟 html += '
  • ' + name + '
  • '; } else { //原生 html += ''; } } } html = data.length > 0 && html ? html : '
  • 您查找的没有此城市...
  • '; return html; }, seTemplet: function () { var config = this.options, selectemplet = '', placeholder, field, forbid, citygrade, active, hide, searchStr = config.search ? '' : ''; for (var i = 0; i < config.level; i++) { //循环定义的级别 placeholder = config.selectpattern[i].placeholder; //默认提示语 field = config.selectpattern[i].field; //字段名称 citygrade = grade[i]; //城市级别名称 forbid = i > 0 ? 'forbid' : ''; //添加鼠标不可点击状态 active = i < 1 ? 'active' : ''; //添加选中状态 hide = i > 0 ? ' hide' : ''; //添加隐藏状态 if (config.renderMode) { //模拟 selectemplet += '
    ' +'' + placeholder + '' +'' +'
    '+ searchStr +'
    ' +'
    '; } else { //原生 selectemplet += ''; } } return selectemplet; }, obtain: function (event) { var self = this, config = self.options, $target = $(event.target), $parent = $target.parents('.listing'), index = config.renderMode ? $target.parents('.storey').data('index') : $target.data('index'), id = config.renderMode ? $target.attr('data-id') : $target.val(), name = config.shorthand ? $target.data('title') : $target.text(), //开启了简写就拿简写,否则就拿全称中文 storage = config.storage ? id : name, //存储的是数字还是中文 code = config.renderMode ? $target.data('code') : $target.find('.caller:selected').data('code'), placeholder = index+1 < config.level ? config.selectpattern[index+1].placeholder : '', placeStr = !config.renderMode ? ''+ effect.montage.apply(self, [config.dataJson, id]) : '
  • '+placeholder+'
  • '+ effect.montage.apply(self, [config.dataJson, id]), linkage = !config.linkage ? placeStr : effect.montage.apply(self, [config.dataJson, id]), $storey = $selector.find('.storey').eq(index + 1), $listing = $selector.find('.listing').eq(index + 1); $selector = self.$selector; //选择选项后触发自定义事件choose(选择)事件 $selector.trigger('choose-' + grade[index] +'.citypicker', [$target, storage]); //赋值给隐藏域-区号 $selector.find('[role="code"]').val(code); if (config.renderMode) { //模拟: 添加选中的样式 $parent.find('.caller').removeClass('active'); $target.addClass('active'); //给选中的级-添加值和文字 $parent.siblings('.reveal').removeClass('df-color forbid').text(name).siblings('.input-price').val(storage); $listing.data('id', id).find('ul').html(linkage).find('.caller').eq(0).trigger('click'); if (!config.linkage) { $storey.find('.reveal').text(placeholder).addClass('df-color').siblings('.input-price').val(''); $listing.find('.caller').eq(0).remove(); } } else { //原生: 下一级附上对应的城市选项,执行点击事件 $target.next().html(linkage).trigger('change').find('.caller').eq(0).prop('selected', true); } }, show: function (event) { var config = this.options, $target = $(event); $selector = this.$selector; $selector.find('.listing').addClass('hide'); $target.siblings('.listing').removeClass('hide'); //点击的回调函数 config.onClickBefore.call($target); }, hide: function (event) { var config = this.options, $target = $(event); effect.obtain.apply(this, $target); $selector.find('.listing').addClass('hide'); }, search: function (event) { var self = this, $target = $(event.target), $parent = $target.parents('.listing'), inputVal = $target.val(), id = $parent.data('id'), result = []; //如果是按下shift/ctr/左右/command键不做事情 if (event.keyCode === 16 || event.keyCode === 17 || event.keyCode === 18 || event.keyCode === 37 || event.keyCode === 39 || event.keyCode === 91 || event.keyCode === 93) { return false; } $.each(this.options.dataJson, function(key, value) { //拼音或者名称搜索 if(value.pinyin.toLocaleLowerCase().search(inputVal) > -1 || value.name.search(inputVal) > -1 || value.id.search(inputVal) > -1 ){ result.push(value); } }); $parent.find('ul').html(effect.montage.apply(self, [result, id])); } }; Citypicker.prototype = { init: function () { var self = this, config = self.options, code = config.code ? '' : ''; //是否开启存储区号,是就加入一个隐藏域 //添加拼接好的模板 $selector.html(effect.seTemplet.call(self) + code); //html模板 if (config.renderMode) { //模拟>添加数据 $selector.find('.listing').data('id', '100000').eq(0).find('ul').html(effect.montage.apply(self, [config.dataJson, '100000'])); } else { //原生>添加数据 $selector.find('.province').append(effect.montage.apply(self, [config.dataJson, '100000'])); } //初始化后的回调函数 config.onInitialized.call(self); }, events: function () { var self = this, config = self.options; //点击显示对应的列表 $selector.on('click.citypicker', '.reveal', function (event) { var $this = $(this); if ($this.is('.forbid')) { config.onForbid.call($this); return false; } effect.show.apply(self, $this); }); //点击选项事件 $selector.on('click.citypicker', '.caller', $.proxy(effect.hide, self)); //原生选择事件 $selector.on('change.citypicker', 'select', $.proxy(effect.obtain, self)); //文本框搜索事件 $selector.on('keyup.citypicker', '.input-search', $.proxy(effect.search, self)); }, setCityVal: function (val) { var self = this, config = self.options, arrayVal = val; $.each(arrayVal, function (key, value) { var $original = $selector.find('.'+grade[key]); var $forward = $selector.find('.'+grade[key+1]); if (config.renderMode) { $original.find('.reveal').text(value.name).removeClass('df-color forbid').siblings('.input-price').val(value.id); $forward.find('ul').html(effect.montage.apply(self, [config.dataJson, value.id])); $original.find('.caller[data-id="'+value.id+'"]').addClass('active'); } else { $forward.html(effect.montage.apply(self, [config.dataJson, value.id])); $original.find('.caller[value="'+value.id+'"]').prop('selected', true); } }); } }; //模拟:执行点击区域外的就隐藏列表; $(document).on('click.citypicker', function (event){ if($selector && $selector.find(event.target).length < 1) { $selector.find('.listing').addClass('hide'); } }); $.fn.cityPicker = function (options) { return new Citypicker(options, this); }; })(jQuery, window);