|
|
/**
|
|
|
* 区域城市级联选择
|
|
|
* @author: dongjinhu(jinhu.dong@yoho.cn)
|
|
|
* @date: 2016/06/30
|
|
|
* @desc:
|
|
|
* 1. 为了减少库的复杂度,应用层的地址接口应该统一并且固定
|
|
|
* @examle:
|
|
|
* CascadingAddress({
|
|
|
* el: '#address',
|
|
|
* resources: 'areas',
|
|
|
* url: '', // 初始化数据请求
|
|
|
* onCreated: function () {} // 初始化完成回调
|
|
|
* })
|
|
|
*/
|
|
|
|
|
|
var $ = require('yoho-jquery');
|
|
|
|
|
|
// 默认配置
|
|
|
var settings = {
|
|
|
url: '',
|
|
|
containerClass: 'cascading-address',
|
|
|
levels: 3,
|
|
|
resources: 'areas',
|
|
|
names: ['province', 'city', 'district'],
|
|
|
indicators: ['请选择省份', '请选择城市', '请选择区/县'],
|
|
|
defaultDes: '加载中...',
|
|
|
ajaxSettings: {
|
|
|
type: 'GET',
|
|
|
url: '',
|
|
|
contentType: 'application/json; charset=utf-8',
|
|
|
dataType: 'json'
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 显示或隐藏下拉区域
|
|
|
function toggleDistItem() {
|
|
|
var $this = $(this),
|
|
|
resetHeight = $this.css('height'),
|
|
|
openHeight = (parseInt(resetHeight.match(/\d*/)[0], 10) + 5) + 'px',
|
|
|
openAndResetHeight = (parseInt(resetHeight.match(/\d*/)[0], 10) - 5) + 'px';
|
|
|
|
|
|
if ($this.hasClass('closed')) {
|
|
|
// 如果有其他开着,先关掉
|
|
|
$('.items-indicator .open').each(function() {
|
|
|
$(this).find('.iconfont').replaceWith('<span class="iconfont up"></span>')
|
|
|
.end()
|
|
|
.removeClass('open')
|
|
|
.addClass('closed')
|
|
|
.css({
|
|
|
height: resetHeight
|
|
|
}).next().hide();
|
|
|
});
|
|
|
|
|
|
// open
|
|
|
$this.find('.iconfont').replaceWith('<span class="iconfont up"></span>')
|
|
|
.end()
|
|
|
.removeClass('closed')
|
|
|
.addClass('open')
|
|
|
.css({
|
|
|
height: openHeight
|
|
|
})
|
|
|
.next()
|
|
|
.show();
|
|
|
|
|
|
// 有视觉差
|
|
|
// setTimeout(function(){
|
|
|
// $('.items-panel').slideDown('fast');
|
|
|
// }, 300)
|
|
|
} else {
|
|
|
// close
|
|
|
$this.find('.iconfont').replaceWith('<span class="iconfont up"></span>')
|
|
|
.end()
|
|
|
.removeClass('open')
|
|
|
.addClass('closed')
|
|
|
.css({
|
|
|
height: openAndResetHeight
|
|
|
}).next().hide();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 重置下一级文本显示和值
|
|
|
function resetNextLevel(level, config) {
|
|
|
$('#level_' + level + '_panel').empty()
|
|
|
.addClass('empty')
|
|
|
.text(config.defaultDes)
|
|
|
.prev().find('.indicator-name')
|
|
|
.text(config.indicators[config.levels - level - 1])
|
|
|
.next().val('');
|
|
|
}
|
|
|
|
|
|
// 获取初始化数据
|
|
|
function fetchInitialData(evt, config, level) {
|
|
|
var distItem, // 请选择...
|
|
|
distItemAreaId = $('.items-indicator .open input').val(),
|
|
|
ajaxSettings = $.extend({}, config.ajaxSettings, {
|
|
|
url: config.url
|
|
|
});
|
|
|
|
|
|
var ulElement = $('<ul/>'),
|
|
|
liElement,
|
|
|
distElement;
|
|
|
|
|
|
var urlArr;
|
|
|
|
|
|
// 当前选中区域id
|
|
|
var currAreaId,
|
|
|
currPanel;
|
|
|
|
|
|
$.ajax(ajaxSettings).done(function(res) {
|
|
|
// 渲染后台区域信息列表
|
|
|
$(res.data).each(function(index, item) {
|
|
|
liElement = $('<li/>');
|
|
|
|
|
|
$('<span class="check-icon iconfont"></span>').appendTo(liElement);
|
|
|
$('<span/>', {
|
|
|
class: 'dist-name',
|
|
|
title: item.text,
|
|
|
text: item.text,
|
|
|
id: 'area_' + item.value
|
|
|
}).appendTo(liElement);
|
|
|
|
|
|
liElement.appendTo(ulElement);
|
|
|
});
|
|
|
|
|
|
// 填充下拉
|
|
|
if (level >= 0) {
|
|
|
currPanel = $('#level_' + level + '_panel');
|
|
|
ulElement.appendTo($(config.el).find('#level_' + level + '_panel').empty().removeClass('empty'));
|
|
|
}
|
|
|
|
|
|
// 选择区域
|
|
|
currPanel.off('click', '.dist-name').on('click', '.dist-name', function() {
|
|
|
distElement = $(this);
|
|
|
currAreaId = distElement.attr('id').split('_')[1];
|
|
|
distItem = $('#level_' + level + '_panel').prev();
|
|
|
|
|
|
if (distElement.hasClass('checked')) {
|
|
|
// TODO
|
|
|
// distElement.removeClass('checked');
|
|
|
} else {
|
|
|
currPanel.find('span.checked').removeClass('checked').prev().hide();
|
|
|
distElement.addClass('checked').prev().show();
|
|
|
distItem.find('.indicator-name')
|
|
|
.html(distElement.text())
|
|
|
.next()
|
|
|
.val(currAreaId);
|
|
|
|
|
|
// 填充下一级
|
|
|
if (level < 0) {
|
|
|
level = distElement.parents('.items-panel').attr('id').split('_')[1];
|
|
|
}
|
|
|
|
|
|
urlArr = config.url.split(config.resources + '/');
|
|
|
urlArr[1] = currAreaId;
|
|
|
config.url = urlArr.join(config.resources + '/');
|
|
|
|
|
|
// 选择之后关闭当前panel
|
|
|
// distItem.trigger('click');
|
|
|
|
|
|
// 当前点击的和已选择的不同,再渲染下一级目录
|
|
|
if (level && distItemAreaId !== currAreaId) {
|
|
|
resetNextLevel(level - 1, config);
|
|
|
$(config.el).trigger('ca.afterInit', [config, level - 1]);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}).fail(function() {
|
|
|
// 如果出错,将下级所有都重置
|
|
|
var from = level;
|
|
|
|
|
|
while (from >= 0) {
|
|
|
resetNextLevel(from, config);
|
|
|
from--;
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 构造器
|
|
|
function CascadingAddress(options) {
|
|
|
var widget = this,
|
|
|
element;
|
|
|
|
|
|
widget.config = $.extend(true, {}, settings, options); // Object.assign({}, settings, options);
|
|
|
element = widget.element = $(widget.config.el);
|
|
|
|
|
|
element.on('ca.afterInit', fetchInitialData);
|
|
|
element.on('click', '.dist-item', toggleDistItem);
|
|
|
|
|
|
// 绑定自定义事件处理
|
|
|
$.each(widget.config, function(key, value) {
|
|
|
if ($.isFunction(value)) {
|
|
|
element.on('ca.' + key, function(evt, params) {
|
|
|
// 处理自定义事件
|
|
|
return value(evt, element, params);
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 初始化
|
|
|
this.init();
|
|
|
}
|
|
|
|
|
|
// 初始化
|
|
|
CascadingAddress.prototype.init = function() {
|
|
|
// 配置
|
|
|
var config = this.config,
|
|
|
el = this.element,
|
|
|
target = el.addClass(config.containerClass),
|
|
|
levels = config.levels;
|
|
|
|
|
|
// DOM相关
|
|
|
var names = config.names,
|
|
|
indicators = config.indicators,
|
|
|
distItem,
|
|
|
inputName,
|
|
|
indicatorName;
|
|
|
|
|
|
// 省份,城市,区县容器
|
|
|
var distItemContainer = $('<ul class="items-indicator"/>'),
|
|
|
liElement,
|
|
|
distPanel;
|
|
|
|
|
|
// ======生成DOM结构======
|
|
|
while (levels--) {
|
|
|
indicatorName = indicators[config.levels - levels - 1];
|
|
|
|
|
|
// li element
|
|
|
liElement = $('<li/>');
|
|
|
|
|
|
// div element
|
|
|
distItem = $('<div></div>', {
|
|
|
class: 'dist-item closed'
|
|
|
});
|
|
|
|
|
|
// 标签
|
|
|
$('<span/>', {
|
|
|
class: 'indicator-name',
|
|
|
text: indicatorName
|
|
|
}).appendTo(distItem);
|
|
|
|
|
|
// input element
|
|
|
inputName = names[config.levels - levels - 1];
|
|
|
$('<input/>', {
|
|
|
type: 'hidden',
|
|
|
name: inputName,
|
|
|
id: inputName,
|
|
|
value: ''
|
|
|
}).appendTo(distItem);
|
|
|
|
|
|
// icon element
|
|
|
$('<span class="iconfont"></span>').appendTo(distItem);
|
|
|
|
|
|
distItem.appendTo(liElement);
|
|
|
|
|
|
// 省份城市区县选择panel
|
|
|
distPanel = $('<div/>', {
|
|
|
class: 'items-panel empty',
|
|
|
id: 'level_' + levels + '_panel',
|
|
|
text: config.defaultDes
|
|
|
});
|
|
|
distPanel.appendTo(liElement);
|
|
|
|
|
|
liElement.appendTo(distItemContainer);
|
|
|
}
|
|
|
|
|
|
distItemContainer.appendTo(target);
|
|
|
|
|
|
// ======生成DOM结构======
|
|
|
|
|
|
// 获取初始化数据
|
|
|
el.trigger('ca.afterInit', [config, config.levels - 1]);
|
|
|
|
|
|
// 初始化完成,提供回调执行
|
|
|
el.trigger('ca.onCreated');
|
|
|
};
|
|
|
|
|
|
module.exports = function(options) {
|
|
|
return new CascadingAddress(options);
|
|
|
}; |
...
|
...
|
|