You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
12 KiB
403 lines
12 KiB
/*!
|
|
* jQuery cxSelect
|
|
* @name jquery.cxselect.js
|
|
* @version 1.4.1
|
|
* @date 2016-11-02
|
|
* @author ciaoca
|
|
* @email ciaoca@gmail.com
|
|
* @site https://github.com/ciaoca/cxSelect
|
|
* @license Released under the MIT license
|
|
*/
|
|
(function(factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
define(['jquery'], factory);
|
|
} else {
|
|
factory(window.jQuery || window.Zepto || window.$);
|
|
};
|
|
}(function($) {
|
|
var cxSelect = function() {
|
|
var self = this;
|
|
var dom, settings, callback;
|
|
|
|
// 分配参数
|
|
for (var i = 0, l = arguments.length; i < l; i++) {
|
|
if (cxSelect.isJquery(arguments[i]) || cxSelect.isZepto(arguments[i])) {
|
|
dom = arguments[i];
|
|
} else if (cxSelect.isElement(arguments[i])) {
|
|
dom = $(arguments[i]);
|
|
} else if (typeof arguments[i] === 'function') {
|
|
callback = arguments[i];
|
|
} else if (typeof arguments[i] === 'object') {
|
|
settings = arguments[i];
|
|
};
|
|
};
|
|
|
|
var api = new cxSelect.init(dom, settings);
|
|
|
|
if (typeof callback === 'function') {
|
|
callback(api);
|
|
};
|
|
|
|
return api;
|
|
};
|
|
|
|
cxSelect.isElement = function(o){
|
|
if (o && (typeof HTMLElement === 'function' || typeof HTMLElement === 'object') && o instanceof HTMLElement) {
|
|
return true;
|
|
} else {
|
|
return (o && o.nodeType && o.nodeType === 1) ? true : false;
|
|
};
|
|
};
|
|
|
|
cxSelect.isJquery = function(o){
|
|
return (o && o.length && (typeof jQuery === 'function' || typeof jQuery === 'object') && o instanceof jQuery) ? true : false;
|
|
};
|
|
|
|
cxSelect.isZepto = function(o){
|
|
return (o && o.length && (typeof Zepto === 'function' || typeof Zepto === 'object') && Zepto.zepto.isZ(o)) ? true : false;
|
|
};
|
|
|
|
cxSelect.getIndex = function(n, required) {
|
|
return required ? n : n - 1;
|
|
};
|
|
|
|
cxSelect.getData = function(data, space) {
|
|
if (typeof space === 'string' && space.length) {
|
|
space = space.split('.');
|
|
for (var i = 0, l = space.length; i < l; i++) {
|
|
data = data[space[i]];
|
|
};
|
|
};
|
|
return data;
|
|
};
|
|
|
|
cxSelect.init = function(dom, settings) {
|
|
var self = this;
|
|
|
|
if (!cxSelect.isJquery(dom) && !cxSelect.isZepto(dom)) {return};
|
|
|
|
var theSelect = {
|
|
dom: {
|
|
box: dom
|
|
}
|
|
};
|
|
|
|
self.attach = cxSelect.attach.bind(theSelect);
|
|
self.detach = cxSelect.detach.bind(theSelect);
|
|
self.setOptions = cxSelect.setOptions.bind(theSelect);
|
|
self.clear = cxSelect.clear.bind(theSelect);
|
|
|
|
theSelect.changeEvent = function() {
|
|
cxSelect.selectChange.call(theSelect, this.className);
|
|
};
|
|
|
|
theSelect.settings = $.extend({}, $.cxSelect.defaults, settings, {
|
|
url: theSelect.dom.box.data('url'),
|
|
emptyStyle: theSelect.dom.box.data('emptyStyle'),
|
|
required: theSelect.dom.box.data('required'),
|
|
firstTitle: theSelect.dom.box.data('firstTitle'),
|
|
firstValue: theSelect.dom.box.data('firstValue'),
|
|
jsonSpace: theSelect.dom.box.data('jsonSpace'),
|
|
jsonName: theSelect.dom.box.data('jsonName'),
|
|
jsonValue: theSelect.dom.box.data('jsonValue'),
|
|
jsonSub: theSelect.dom.box.data('jsonSub')
|
|
});
|
|
|
|
var _dataSelects = theSelect.dom.box.data('selects');
|
|
|
|
if (typeof _dataSelects === 'string' && _dataSelects.length) {
|
|
theSelect.settings.selects = _dataSelects.split(',');
|
|
};
|
|
|
|
self.setOptions();
|
|
self.attach();
|
|
|
|
// 使用独立接口获取数据
|
|
if (!theSelect.settings.url && !theSelect.settings.data) {
|
|
cxSelect.start.apply(theSelect);
|
|
|
|
// 设置自定义数据
|
|
} else if ($.isArray(theSelect.settings.data)) {
|
|
cxSelect.start.call(theSelect, theSelect.settings.data);
|
|
|
|
// 设置 URL,通过 Ajax 获取数据
|
|
} else if (typeof theSelect.settings.url === 'string' && theSelect.settings.url.length) {
|
|
$.getJSON(theSelect.settings.url, function(json) {
|
|
cxSelect.start.call(theSelect, json);
|
|
});
|
|
};
|
|
};
|
|
|
|
// 设置参数
|
|
cxSelect.setOptions = function(opts) {
|
|
var self = this;
|
|
|
|
if (opts) {
|
|
$.extend(self.settings, opts);
|
|
};
|
|
|
|
// 初次或重设选择器组
|
|
if (!$.isArray(self.selectArray) || !self.selectArray.length || (opts && opts.selects)) {
|
|
self.selectArray = [];
|
|
|
|
if ($.isArray(self.settings.selects) && self.settings.selects.length) {
|
|
var _tempSelect;
|
|
|
|
for (var i = 0, l = self.settings.selects.length; i < l; i++) {
|
|
_tempSelect = self.dom.box.find('select.' + self.settings.selects[i]);
|
|
|
|
if (!_tempSelect || !_tempSelect.length) {break};
|
|
|
|
self.selectArray.push(_tempSelect);
|
|
};
|
|
};
|
|
};
|
|
|
|
if (opts) {
|
|
if (!$.isArray(opts.data) && typeof opts.url === 'string' && opts.url.length) {
|
|
$.getJSON(self.settings.url, function(json) {
|
|
cxSelect.start.call(self, json);
|
|
});
|
|
|
|
} else {
|
|
cxSelect.start.call(self, opts.data);
|
|
};
|
|
};
|
|
};
|
|
|
|
// 绑定
|
|
cxSelect.attach = function() {
|
|
var self = this;
|
|
|
|
if (!self.attachStatus) {
|
|
self.dom.box.on('change', 'select', self.changeEvent);
|
|
};
|
|
|
|
if (typeof self.attachStatus === 'boolean') {
|
|
cxSelect.start.call(self);
|
|
};
|
|
|
|
self.attachStatus = true;
|
|
};
|
|
|
|
// 移除绑定
|
|
cxSelect.detach = function() {
|
|
var self = this;
|
|
self.dom.box.off('change', 'select', self.changeEvent);
|
|
self.attachStatus = false;
|
|
};
|
|
|
|
// 清空选项
|
|
cxSelect.clear = function(index) {
|
|
var self = this;
|
|
var _style = {
|
|
display: '',
|
|
visibility: ''
|
|
};
|
|
|
|
index = isNaN(index) ? 0 : index;
|
|
|
|
// 清空后面的 select
|
|
for (var i = index, l = self.selectArray.length; i < l; i++) {
|
|
self.selectArray[i].empty().prop('disabled', true);
|
|
|
|
if (self.settings.emptyStyle === 'none') {
|
|
_style.display = 'none';
|
|
} else if (self.settings.emptyStyle === 'hidden') {
|
|
_style.visibility = 'hidden';
|
|
};
|
|
|
|
self.selectArray[i].css(_style);
|
|
};
|
|
};
|
|
|
|
cxSelect.start = function(data) {
|
|
var self = this;
|
|
|
|
if ($.isArray(data)) {
|
|
self.settings.data = cxSelect.getData(data, self.settings.jsonSpace);
|
|
};
|
|
|
|
if (!self.selectArray.length) {return};
|
|
|
|
// 保存默认值
|
|
for (var i = 0, l = self.selectArray.length; i < l; i++) {
|
|
if (typeof self.selectArray[i].attr('data-value') !== 'string' && self.selectArray[i][0].options.length) {
|
|
self.selectArray[i].attr('data-value', self.selectArray[i].val());
|
|
};
|
|
};
|
|
|
|
if (self.settings.data || (typeof self.selectArray[0].data('url') === 'string' && self.selectArray[0].data('url').length)) {
|
|
cxSelect.getOptionData.call(self, 0);
|
|
} else {
|
|
self.selectArray[0].prop('disabled', false).css({
|
|
'display': '',
|
|
'visibility': ''
|
|
});
|
|
};
|
|
};
|
|
|
|
// 获取选项数据
|
|
cxSelect.getOptionData = function(index) {
|
|
var self = this;
|
|
|
|
if (typeof index !== 'number' || isNaN(index) || index < 0 || index >= self.selectArray.length) {return};
|
|
|
|
var _indexPrev = index - 1;
|
|
var _select = self.selectArray[index];
|
|
var _selectData;
|
|
var _valueIndex;
|
|
var _dataUrl = _select.data('url');
|
|
var _jsonSpace = typeof _select.data('jsonSpace') === 'undefined' ? self.settings.jsonSpace : _select.data('jsonSpace');
|
|
var _query = {};
|
|
var _queryName;
|
|
var _selectName;
|
|
var _selectValue;
|
|
|
|
cxSelect.clear.call(self, index);
|
|
|
|
// 使用独立接口
|
|
if (typeof _dataUrl === 'string' && _dataUrl.length) {
|
|
if (index > 0) {
|
|
for (var i = 0, j = 1; i < index; i++, j++) {
|
|
_queryName = self.selectArray[j].data('queryName');
|
|
_selectName = self.selectArray[i].attr('name');
|
|
_selectValue = self.selectArray[i].val();
|
|
|
|
if (typeof _queryName === 'string' && _queryName.length) {
|
|
_query[_queryName] = _selectValue;
|
|
} else if (typeof _selectName === 'string' && _selectName.length) {
|
|
_query[_selectName] = _selectValue;
|
|
};
|
|
};
|
|
};
|
|
|
|
$.getJSON(_dataUrl, _query, function(json) {
|
|
_selectData = cxSelect.getData(json, _jsonSpace);
|
|
|
|
cxSelect.buildOption.call(self, index, _selectData);
|
|
});
|
|
|
|
// 使用整合数据
|
|
} else if (self.settings.data && typeof self.settings.data === 'object') {
|
|
_selectData = self.settings.data;
|
|
|
|
for (var i = 0; i < index; i++) {
|
|
_valueIndex = cxSelect.getIndex(self.selectArray[i][0].selectedIndex, typeof self.selectArray[i].data('required') === 'boolean' ? self.selectArray[i].data('required') : self.settings.required);
|
|
|
|
if (typeof _selectData[_valueIndex] === 'object' && $.isArray(_selectData[_valueIndex][self.settings.jsonSub]) && _selectData[_valueIndex][self.settings.jsonSub].length) {
|
|
_selectData = _selectData[_valueIndex][self.settings.jsonSub];
|
|
} else {
|
|
_selectData = null;
|
|
break;
|
|
};
|
|
};
|
|
|
|
cxSelect.buildOption.call(self, index, _selectData);
|
|
};
|
|
};
|
|
|
|
// 构建选项列表
|
|
cxSelect.buildOption = function(index, data) {
|
|
var self = this;
|
|
|
|
var _select = self.selectArray[index];
|
|
var _required = typeof _select.data('required') === 'boolean' ? _select.data('required') : self.settings.required;
|
|
var _firstTitle = typeof _select.data('firstTitle') === 'undefined' ? self.settings.firstTitle : _select.data('firstTitle');
|
|
var _firstValue = typeof _select.data('firstValue') === 'undefined' ? self.settings.firstValue : _select.data('firstValue');
|
|
var _jsonName = typeof _select.data('jsonName') === 'undefined' ? self.settings.jsonName : _select.data('jsonName');
|
|
var _jsonValue = typeof _select.data('jsonValue') === 'undefined' ? self.settings.jsonValue : _select.data('jsonValue');
|
|
|
|
if (!$.isArray(data)) {return};
|
|
|
|
var _html = !_required ? '<option value="' + String(_firstValue) + '">' + String(_firstTitle) + '</option>' : '';
|
|
|
|
// 区分标题、值的数据
|
|
if (typeof _jsonName === 'string' && _jsonName.length) {
|
|
// 无值字段时使用标题作为值
|
|
if (typeof _jsonValue !== 'string' || !_jsonValue.length) {
|
|
_jsonValue = _jsonName;
|
|
};
|
|
|
|
for (var i = 0, l = data.length; i < l; i++) {
|
|
_html += '<option value="' + String(data[i][_jsonValue]) + '">' + String(data[i][_jsonName]) + '</option>';
|
|
};
|
|
|
|
// 数组即为值的数据
|
|
} else {
|
|
for (var i = 0, l = data.length; i < l; i++) {
|
|
_html += '<option value="' + String(data[i]) + '">' + String(data[i]) + '</option>';
|
|
};
|
|
};
|
|
|
|
_select.html(_html).prop('disabled', false).css({
|
|
'display': '',
|
|
'visibility': ''
|
|
});
|
|
|
|
// 初次加载设置默认值
|
|
if (typeof _select.attr('data-value') === 'string') {
|
|
_select.val(String(_select.attr('data-value'))).removeAttr('data-value');
|
|
|
|
if (_select[0].selectedIndex < 0) {
|
|
_select[0].options[0].selected = true;
|
|
};
|
|
};
|
|
|
|
if (_required || _select[0].selectedIndex > 0) {
|
|
_select.trigger('change');
|
|
};
|
|
|
|
};
|
|
|
|
// 改变选择时的处理
|
|
cxSelect.selectChange = function(name) {
|
|
var self = this;
|
|
|
|
if (typeof name !== 'string' || !name.length) {return};
|
|
|
|
var index;
|
|
|
|
name = name.replace(/\s+/g, ',');
|
|
name = ',' + name + ',';
|
|
|
|
// 获取当前 select 位置
|
|
for (var i = 0, l = self.selectArray.length; i < l; i++) {
|
|
if (name.indexOf(',' + self.settings.selects[i] + ',') > -1) {
|
|
index = i;
|
|
break;
|
|
};
|
|
};
|
|
|
|
if (typeof index === 'number' && index > -1) {
|
|
index += 1;
|
|
cxSelect.getOptionData.call(self, index);
|
|
};
|
|
};
|
|
|
|
$.cxSelect = function() {
|
|
return cxSelect.apply(this, arguments);
|
|
};
|
|
|
|
// 默认值
|
|
$.cxSelect.defaults = {
|
|
selects: [], // 下拉选框组
|
|
url: null, // 列表数据文件路径(URL)或数组数据
|
|
data: null, // 自定义数据
|
|
emptyStyle: null, // 无数据状态显示方式
|
|
required: false, // 是否为必选
|
|
firstTitle: '请选择', // 第一个选项的标题
|
|
firstValue: '', // 第一个选项的值
|
|
jsonSpace: '', // 数据命名空间
|
|
jsonName: 'n', // 数据标题字段名称
|
|
jsonValue: '', // 数据值字段名称
|
|
jsonSub: 's' // 子集数据字段名称
|
|
};
|
|
|
|
$.fn.cxSelect = function(settings, callback) {
|
|
this.each(function(i) {
|
|
$.cxSelect(this, settings, callback);
|
|
});
|
|
return this;
|
|
};
|
|
}));
|
|
|