/*
* 基于jquery级联选择
* target: 下一级的jquery选择器
* urlOrData: ajax请求的url或用于刷选的Data
* options: 配置
*/
(function($) {
var defaultOptions = {
after: null,
before: null,
usePost: false,
defaultValue: null,
filter: null,
preValue: '-1',
preText: '请选择',
groupSort: 'desc',
order: 'name asc',
params: {},
dataMap: {'text': 'text', 'value': 'value', 'group': 'group'}
};
var missGroup = '__MISS__';
var dataToOption = function(data, op) {
var d = [], vs = [], hasFilter = op.filter && $.isFunction(op.filter);
$.each(data, function(i, v) {
if(!hasFilter || (hasFilter && op.filter(v, i))) {
if($.inArray(v[op.dataMap.value], vs) == -1) {
d.push($.extend({}, v));
vs.push(v[op.dataMap.value]);
}
}
});
if(op.order) {
var sp = op.order.split(' '), col = sp[0], sort = sp[1].toLowerCase() == 'asc' ? 1 : -1;
d.sort(function(a, b) {
if(a[col] > b[col]) {
return sort;
} else if(a[col] < b[col]) {
return -sort;
} else {
return 0;
}
});
}
var ops = '', gps = groupData(mapData(d, op.dataMap));
var createOption = function(items) {
var _ops = '';
if(!$.isArray(items)) {
items = [items];
}
$.each(items, function(i, v) {
_ops += '<option value="' + v['value'] + '">' + v['text'] + '</option>';
});
return _ops;
};
var createGroup = function(group, options) {
return '<optgroup label="' + group + '"></optgroup>' + options;
};
if(op.preValue || op.preText) {
ops += createOption({'value': op.preValue, 'text': op.preText});
}
if(gps[missGroup] != undefined) {
ops += createOption(gps[missGroup]);
delete gps[missGroup];
}
if(op.groupSort == 'desc') {
gps['keys'].sort().reverse();
} else if(op.groupSort == 'asc') {
gps['keys'].sort()
}
$.each(gps['keys'], function(i, v) {
ops += createGroup(v, createOption(gps[v]));
});
return ops;
};
var mapData = function(data, map) {
$.each(data, function(i, v) {
$.each(map, function(j, k) {
if(v[j] == undefined) {
data[i][j] = v[k] == undefined ? '' : v[k];
delete data[i][k];
}
});
});
return data;
};
var groupData = function(data) {
var gps = {};
gps['keys'] = [];
var pushData = function(group, item) {
if(gps[group] == undefined) {
gps[group] = [];
}
gps[group].push(item);
};
var pushKey = function(key) {
if($.inArray(key, gps['keys']) == -1) {
gps['keys'].push(key);
}
};
$.each(data, function(i, v) {
if(v['group']) {
pushKey(v['group']);
pushData(v['group'], v);
} else {
pushData(missGroup, v);
}
});
return gps;
};
$.fn.fillselect = function(urlOrData, options) {
return this.each(function() {
var $t = $(this), op, dataReadyCallback, ajaxXHR = null;
op = $.extend(true, {}, defaultOptions, options);
$t.data('fillselectOptions', op);
if(op.before && $.isFunction(op.before)) {
op.before.apply($t);
}
dataReadyCallback = function(data) {
$t.html(dataToOption(data, op));
if(op.defaultValue) {
$t.val(op.defaultValue);
}
if(op.after && $.isFunction(op.after)) {
op.after.apply($t);
}
$t.trigger('change');
};
if(typeof urlOrData == 'string') {
if(ajaxXHR) {
ajaxXHR.abort();
}
ajaxXHR = $.ajax({
'url': urlOrData,
'type': op.usePost ? 'post' : 'get',
'data': op.params,
'dataType': 'json',
'success': function(data) {
ajaxXHR = null;
if(data.status == '200') {
dataReadyCallback(data.data || []);
}
},
'error': function() {
ajaxXHR = null;
}
});
} else {
dataReadyCallback(urlOrData);
}
});
};
$.fn.chainselect = function(target, urlOrData, options) {
return this.each(function() {
$(this).bind('change', function() {
var $t = $(this), op;
op = $.extend(true, {}, defaultOptions , options);
op.params[$t.attr('name') || $t.attr('id')] = $t.val();
op.params['id'] = $t.val();
if($t.val() != $t.data('fillselectOptions').preValue) {
$(target).fillselect(urlOrData, op);
} else {
op.after = null;
$(target).fillselect([], op);
}
});
});
}
})(jQuery);此段代码实际上包含了两个jq插件,第一个是fillselect用于填充select,支持data或url(ajax)的方式;第二个是chainselect用于级联select。下面就详细介绍一下这段代码:
var defaultOptions = {
after: null,
before: null,
usePost: false,
defaultValue: null,
filter: null,
preValue: '-1',
preText: '請選擇',
groupSort: 'desc',
order: 'name asc',
params: {},
dataMap: {'text': 'text', 'value': 'value', 'group': 'group'}
};插件的默认参数配置
after:select数据载入结束事件callback
before:数据载入前事件callback
usePost:ajax请求方式,默认为GET
defaultValue:默认选中的值
filter:数据过滤函数,类似jq的grep方法,使用方式也是一样的,第一个参数为value,第二个参数为key或index,当返回值为false即过滤掉该条数据,如:filter: function(v, i) { return v.count > 1; }过滤数据中count属性小于1的数据
preValue,preText:初始option的值和文字
groupSort:分组optgroup排序方式
order:数据的排序方式,排序字段与方向空格隔开
params:随ajax请求传递的参数
dataMap:数据属性映射,目的提高插件对数据的自适应性,如真实数据是name,id,year,则dataMap: { 'text': 'name', 'value': 'id', 'group': 'year' };如果不使用分组功能,只需保留text和value
missGroup:缺省分组名;
dataToOption:用于将数据转换成option;
mapData:将数据转成统一格式;
groupData:将数据分组;
这段实现逻辑略显冗长,因为实际项目中的需求多变,这个可根据实际需求简化一下代码。
$.fn.fillselect在dataReadyCallback中触发change事件主要目的是使此select的下一级生效;
$.fn.chainselect多了一个target参数用于指向下一级的jq选择器。
那么现在来看下怎么使用,需求:厂牌brand->车款kind->车型model,ajax获取的数据格式为{status: 200, data: [{id: 1, name: 'bmw'}, {id: 2, name: 'benz'}]};车型的数据需要根据year_name分组
<select name="brand" id="brand"></select> <select name="kind" id="kind" disabled></select> <select name="model" id="model" disabled></select>
$('#brand').chainselect('#kind', '/request_url', {
'dataMap': {'value': 'id', 'text': 'name'},
'preValue': -1,
'preText': '選擇/車款',
'params': {'type': '_cache_kind'},
'before': function() {
this.attr('disabled', true);
},
'after': function() {
this.removeAttr('disabled');
},
'defaultValue': lastKindId || -1
});
$('#kind').chainselect('#model', '/request_url', {
'dataMap': {'value': 'myid', 'text': 'name', 'group': 'year_name'},
'preValue': -1,
'preText': '選擇/車型',
'params': {'type': '_cache_model'},
'filter': function(v, i) {
return $.inArray(v.myid, myids) === -1;
},
'before': function() {
this.attr('disabled', true);
},
'after': function() {
this.removeAttr('disabled');
}
});
$('#brand').fillselect('/request_url', {
'dataMap': {'value': 'id', 'text': 'name'},
'preValue': -1,
'preText': '選擇/廠牌',
'params': {'type': '_cache_brand'},
'defaultValue': lastBrandId || -1
});


喜欢
顶
难过
囧
围观
无聊



