/* style基础样式 */
.menuDownWarp{
position: absolute;
margin: 6px 0 0 -10px;
background-color: #fff;
border: 1px solid #e3e3e3;
width: 160px;
}
.menuDownWarp .on{
background-color: #f0f0f0;
}
.menuDownWarp li{
padding: 0 5px;
line-height: 30px;
cursor: pointer;
}
// 可以指定skin参数,通过修改样式中的margin值来修正定位等一些样式
// 创建菜单示例
callback : function(msg){
msg = msg || [];
var htm = '<li class="on g-hidden">' + this.val() + '</li>';
for( var i = 0,l = msg.length;i < l; i++ ){
htm += '<li data-id="'+msg[i].brand_id+'">' + msg[i].brand_name + '</li>';
}
return htm;
}
// 创建的菜单项带有额外复杂数据示例
callback : function(msg){
msg = msg || [];
var htm = $('<li class="on g-hidden">' + this.val() + '</li>');
for( var k in msg ) {
htm = htm.add($('<li>' + k + '</li>').data('db',msg[k]));
}
return htm;
},
enterMenu : function($e){
// 菜单项带的额外复杂数据
$e.data('db');
}
/**
* 【功能描述】
* 下拉框选择
* 插件参数是一个对象
* html对象要添加自定义属性getdataurl,指定ajax获取数据的url
* callback:方法返回li标签的html字符串菜单选项,第一个li标签要给class加上参数的active值并且隐藏,值为输入框的默认值(键盘上下键时可以选到默认值),函数上下文是输入框,参数可以是异步getdataurl获取回来的数据也可以是直接传递待处理的data参数
* data:可以直接传递待处理的数据过来
* toSelectListData:用户在下拉框中做选择更改输入框值时执行的函数,函数的上下文是输入框,参数是当前选择的那一个li标签对象
* toUserInputData:当用户选择自己输入的数据时要执行的函数,函数上下文是输入框
* enterMenu:当最终确认选择了一条数据后要执行的函数(不论选择哪一条数据),函数上下文是输入框,参数是当前选择的那一个li标签对象
* enter:按回车键时是否自动触发提交表单动作,默认不触发提交
* skin:用来用户自定义样式的class属性,默认menuDownWarp(注意都是class名,不带.)
* active:激活选项的class属性,默认on(注意都是class名,不带.)
*/
$.fn.menuSel = function(option){
var def = {
skin : 'menuDownWarp',
active : 'on',
toSelectListData : function(){},
toUserInputData : function(){},
enterMenu : function(){},
enter : false,
data : null
};
var o = $.extend(def,option || {});
var $wrap = $('<ul class="' + o.skin + '"></ul>').appendTo('body');
this.each(function(){
var $t = $(this);
var $e;
// 确保如果异步请求处理数据时,当网络速度慢时,失去焦点能够保证隐藏下拉框
$t.posting = true;
// 保证按键后值有变化才会触发下拉修改请求(中文输入多个拼音才会改变内容)
$t.oldval = $.trim($t.val());
$t.keydown(function(e){
var keyCode = e.keyCode;
var $child = $wrap.children();
var $on = $child.filter('.'+o.active);
var datalist = o.data;
var execFn = {
'40' : 'next',
'38' : 'prev'
};
var $addon;
var fixPosi = {
'40' : ':first',
'38' : ':last'
};
// 上下键
if ( keyCode === 38 || keyCode === 40 ) {
// 通过键盘操作找到要添加on的元素
$addon = $on[execFn[keyCode]]();
// 如果没找到,就根据键盘操作找直接定位到第一或最后一个
if ( !$addon.length ) {
$addon = $on.siblings(fixPosi[keyCode])
}
$e = $addon;
// 给找到的元素加上class
_addActive();
// 当更改输入框值时执行的函数
_changeval();
return false;
} else if ( keyCode === 13 ) { // 回车
// 隐藏下拉框
$t.blur();
if ( o.enter ) {
$t.closest('form').submit();
}
return false;
}
}).keyup(function(e){
var keyCode = e.keyCode;
var ajaxurl = $t.attr('getdataurl');
function _addMenu(htm){
$t.posting = true;
htm = $(htm);
// 如果只有一个默认值没有更多选项就直接隐藏下拉并退出函数
if ( htm.length === 1 ) {
$wrap.hide();
return false;
}
// 第一个li隐藏,文本内容为用户输入的
$wrap.html(htm);
// 定位下拉框的位置并显示
$wrap.css({
left : $t.offset().left,
top : $t.offset().top + $t.height()
}).show().children().click(function(){
$e = $(this);
// 当更改输入框值时执行的函数
_changeval();
}).mouseover(function(){
$e = $(this);
_addActive();
});
}
// 当输入为非回车时,并且不是按的上下键,并且按键后与按键前的值不同
if ( keyCode !== 13 && keyCode !== 38 && keyCode !== 40 && $t.oldval != $.trim($t.val()) ) {
$t.oldval = $.trim($t.val());
$t.posting = false;
o.toUserInputData.call($t);
// 如果直接传了待处理数据
if ( o.data !== null ) {
_addMenu(o.callback.call($t,datalist));
} else if ( ajaxurl ) { // 如果有异步请求数据地址
$.ajax({
url : ajaxurl,
data : $t.serialize(),
dataType : 'json',
type : 'post',
success : function(msg){
_addMenu(o.callback.call($t,datalist = msg));
}
});
}
}
}).blur(function(){
// 隐藏下拉框
var timer = setInterval(function(){
if ( $t.posting ) {
$wrap.hide();
clearTimeout(timer);
// 如果选择了菜单项,输入后要执行的函数
$e && o.enterMenu.call($t,$e);
}
}, 100)
});
function _addActive(){
var cname = o.active;
$e.addClass(o.active).siblings().removeClass(o.active);
}
// 改变输入框值时执行的函数
function _changeval(){
var val = $.trim($e.text());
// 从菜单中选择值
if ( $e.index() > 0 ) {
o.toSelectListData.call($t,$e);
} else {
// 如果是自己输入的值非菜单选择值
o.toUserInputData.call($t);
}
// _changeval.item = $e;
// 输入框的值与选择的记录同步
$t.val(val);
}
})
}