`
shuaijie506
  • 浏览: 137767 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

一个基于jquery的简单下拉框实现

 
阅读更多

项目中使用的是easyui的组件,后来发现在编辑页面中,如果combobox组件数量过多,会导致页面超级慢,还有可能造成浏览器崩溃,经过研究easyui的源码发现,combobox是由多个html对象组成的,而且每个combobox有一个单独的下拉面板,如果页面上有100个下拉框组件,每个组件中有500个元素,这样一个页面中隐藏的下拉面板中就会有50000个下拉元素对象,怪不得页面那么慢呢,前一段有时间就自己写了一个简单的下拉框,为与combobox区别,取名叫scombobox,实现的原理是页面中所有下拉框共用一个下拉面板,面板中的内容根据内容自动筛选,并能根据输入的拼音进行模糊匹配并用着重色标识出来,而控件则仍使用<input type=text>,只不过给它加上了下拉框的样式,这样感觉就简单了好多,最后效果也不错,附件中是一个完整的演示例子。

 

亲测在IE6、IE8、IE9、Chrome23、Firefox17、Oprea12下可用

 

jQuery.basePath=function(filename){
	var eles = document.getElementsByTagName('script');
	for(var i=0;i<eles.length;i++){
		var src = eles[i].getAttribute('src');
		if(src&&src.indexOf(filename)==src.length-filename.length){
			return src.substr(0,src.indexOf(filename));
		}
	}
};
(function($){
	$.fn.scombobox = function(opt,data){
		if(typeof(opt)=='string'){
			return $.fn.scombobox.method[opt](this,data);
		}
		else{
			return $.fn.scombobox.method.init(this,opt);
		}
	};
	$.fn.scombobox.defaults={panels:{},valueField:'id',textField:'text',width:'auto',panelWidth:'auto',panelHeight:150,
			value:null,multiple:false,separator:',',editable:true,disabled:false,maxOptions:50,
			filter:function(key,row){
				if(!key)return {position:0,length:0};
				if((pos=row[this.textField].indexOf(key))>=0){
					var ary = [key];ary.position=pos;
					return ary;
				}
				return $.pinyin?$.pinyin.filter(row[this.textField],key):false;
			}
	};
	$.fn.scombobox.method={
			init:function(target,options){
				return init(target,options);
			},
			options:function(target){
				return target.data('options');
			},
			getValue:function(target){
				return $(target[0]).data('scombo-val').val();
			},
			getValues:function(target){
				return $(target[0]).data('scombo-val').val().split($(target[0]).data('options').separator);
			},
			getText:function(target){
				return target.val();
			},
			setValue:function(target,val){
				validate(target,true);
				var valInput = $(target[0]).data('scombo-val').val(val);
				changeEvt($(target[0]),valInput);
				return target;
			},
			setValues:function(target,val){
				validate(target,true);
				var valInput = $(target[0]).data('scombo-val').val(val.constructor==Array?val.join($(target[0]).data('options').separator):val);
				changeEvt($(target[0]),valInput);
				return target;
			},
			setText:function(target,text){
				validate(target,true);
				return target.val(text);
			},
			valuebox:function(target){
				return target.data('scombo-val');
			},
			remove:function(target){
				target.data('scombo-val').remove();
				return target.remove();
			},
			showPanel:function(target,event){//触发面板显示的事件
				return showPanel(target,event);
			},
			hidePanel:function(target){
				validate(target,true);
				var th = $(target),div=th.data('scombo-panel');
				div.hide();
				changeEvt(th);
				return th;
			},
			disable:function(target){
				target.data('options').disabled=true;
				$(document).trigger('click',[true]);
				return target.attr('disabled',true);
			},
			enable:function(target){
				target.data('options').disabled=false;
				validate(target,true);
				return target.attr('disabled',false);
			},
			editable:function(target,editable){
				target.data('options').editable=editable;
				validate(target,true);
				return target;
			}
	};
	function init(target,options){
		if(!$.pinyin){
			$.getScript($.basePath('jquery.easyui.min.js')+'pinyin.js');
		}
		var opt = $.extend({},$.fn.scombobox.defaults,options);
		target.attr('autocomplete', 'off').data('options',opt).unbind('.scombo');
		if(!$.fn.scombobox.defaults._panel){//如果还没有创建面板,则新建面板
			var div =$.fn.scombobox.defaults._panel= $('<div class="scombo-panel"></div>').appendTo('body').bind('mousedown',function(){return false;});
			div.hide();
		}
		target.bind('dataloaded.scombo',dataloadedEvent);
		validate(target,true);
		target.data('scombo-panel',$.fn.scombobox.defaults._panel);//将下拉面板绑定到输入框上
		target.each(function(){
			var th=$(this),opt=$.extend({},$.fn.scombobox.defaults,parseOption(this),options);
			th.data('options',opt);
			var valInput = $('<input type=hidden >').attr('name',th.attr('name')).insertBefore(this);
			if(th.attr('tagName').toLowerCase()=='select'){//如果是select,需要将Select隐藏,显示input
				th = $('<input type=text autocomplete=off>').insertBefore(this).bind('dataloaded.scombo',dataloadedEvent).data('options',opt).data('scombo-panel',$.fn.scombobox.defaults._panel);
				var domAttrs = {type:true,outerHTML:true,innerHTML:true,outerText:true,innerText:true,tagName:true,textContent:true,localName:true,nodeName:true,baseURI:true,namespaceURI:true};
				for(var p in this){
					try{if(this[p]&&!domAttrs[p]&&typeof(this[p])=='string')th.attr(p,this[p]);}catch(e){;}
				}
				th.attr('style',$(this).attr('style'));
				$(this).remove();
				target.push(th[0]);
			}
			//设定隐藏域的值
			valInput.val(getVal(opt.value,th.val()));
			th.addClass('scombo-box').attr('readonly',opt.disabled).attr('scombo-name',th.attr('name')).removeAttr('name').val('')
					.data('scombo-val',valInput).data('old-val',valInput.val()).bind('click.scombo focus.scombo paste.scombo keyup.scombo type.scombo',function(event){
				$.fn.scombobox.method.showPanel(this,event);return $.event.fix(event).type=='paste';//只有粘贴事件冒泡,其它事件不冒泡
			});
			if(opt.width&&opt.width!='auto'){//处理宽度
				var wid=getVal(opt.width,th.outerWidth());
				th.width(wid);
				if(th.outerWidth()!=wid){//防止不同盒子模型解析的宽度不一致
					th.width(wid-(th.outerWidth()-wid)).height(18);
				}
			}
		});
		if(opt.url){//最后再从服务器加载内容,以免取不到VALUE隐藏字段
			$.post(opt.url,opt.params,function(data){
				try{
					var ary = $.parseJSON(data);
				}
				catch(e){;}
				opt.data = ary||data;
				target.trigger('dataloaded');//触发数据加载成功事件
			});
		}
		else{//触发数据加载成功事件
			target.trigger('dataloaded');
		}
		return target;
	}
	function showPanel(target,event){
		var th = $(target),div=th.data('scombo-panel'),opt=th.data('options');
		if(!opt||opt.disabled)return th;//禁用时直接返回,不显示下拉面板
		var pos = th.offset();
		pos.top+=th.outerHeight()+2;
		pos.width = getVal(opt.panelWidth,th.outerWidth()-1);
		pos.height = getVal(opt.panelHeight,'');
		div.css(pos);//定位
		if(event){
			var evt = $.event.fix(event),kc=evt.keyCode;
			if(evt.type!='click'&&evt.type!='focus'){
				if(kc==13){//回车
					if((item=$('.hover',div)).length>0){
						th.val(item.text());
						th.data('scombo-val').val(item.attr('value'));
						th.removeData('keypress');
						$(document).trigger('click',[true]);
						return;
					}
				}
				else if(kc==38){//向上
					if($('.hover',div).length==0){
						var item=$('.scombo-item:last',div).addClass('hover');
						makeCenter(div,$('.hover:first',div));
					}
					else{
						var item = $('.hover',div);
						if(item.prev().length>0){
							makeCenter(div,$('.hover:first',div));
							item.removeClass('hover').prev().addClass('hover');
						}
					}
					return;
				}
				else if(kc==40){//向下
					if($('.hover',div).length==0){
						$('.scombo-item:first',div).addClass('hover');
						makeCenter(div,$('.hover:first',div));
					}
					else{
						var item = $('.hover',div);
						if(item.next().length>0){
							makeCenter(div,$('.hover:first',div));
							item.removeClass('hover').next().addClass('hover');
						}
					}
					return;
				}//非控制按键和功能按键8==BACKSPACE,32=SPACE,48-57=0-9,65-90=A-Z,96-111=小键盘,186-222=大键盘上的特殊字符
				else if(kc==8||kc==32||(kc>=48&&kc<=111)||kc>=186){
					th.data('keypress',1);
				}
			}
		}
		var key = event&&(evt.type=='keyup'||evt.type=='type')?th.val():null;//非键盘事件触发时,展开所有选项
		if((div.data('scombo-box')&&div.data('scombo-box')[0]!=th[0])||div.data('scombo-box',th).css('display')=='none'){
			if(div.data('scombo-box')&&div.data('scombo-box')[0]!=th[0]){
				$(document).trigger('click',[true]);
				div.data('scombo-box',th);
			}
			$(document).bind('mousedown.scombo',function (event,hidePanel){//页面中其他位置的点击事件,点击后隐藏下拉面板
				var obj = $($.event.fix(event).target);
				if(!$.fn.scombobox.defaults._panel){
					return;
				}
				var th = $.fn.scombobox.defaults._panel.data('scombo-box');
				if(!hidePanel&&th[0]==obj[0]){
					return;
				}
				var opt = th.data('options');
				if(th.data('keypress')){//如果用户使用键盘输入了,则进行显示值处理
					if(opt.editable){//可写时,将写入的内容存到VALUE字段中
						th.data('scombo-val').val(th.val());
					}
					else{
						var text = '',vals=th.data('scombo-val').val().split(opt.separator);
						for(var i=0;i<opt.data.length;i++){
							if((pos=vals.indexOf(opt.data[i][opt.valueField]))>=0){
								text+=opt.separator+opt.data[i][opt.textField];
								vals.splice(pos,1);
							}
						}
						th.val(text.substr(opt.separator.length));
					}
				}
				changeEvt(th);
				$.fn.scombobox.defaults._panel.removeData('last-key').removeData('keypress').hide();
				$(document).unbind('mousedown.scombo');//解绑本事件
			});
			fillData(div,opt,null);//第一次显示下拉选项时,展开所有选项
		}
		if(div.data('last-key')!=key){
			div.data('last-key',key);
			fillData(div,opt,key);
		}
		return th;
	}
	function changeEvt(th,valInput){
		if(!th||th.length==0)return;
		valInput=valInput||th.data('scombo-val');
		if(valInput.val()!=valInput.data('old-val')){
			th.trigger('change',[valInput.val(),valInput.data('old-val')]);
			valInput.data('old-val',valInput.val());
		}
	}
	function parseOption(target){
		var th = $(target),opt={};
		for(var p in $.fn.scombobox.defaults){
			var val = th.attr(p)+'',dval=$.fn.scombobox.defaults[p];
			if(th.attr(p)){
				opt[p] = val;
				if(typeof(dval)=='boolean')opt[p]=val=='true';
				else if(typeof(dval)!='string')try{opt[p]=eval(val);}catch(e){;}
			}
		}
		if(!opt.data&&th.attr('tagName')=='SELECT'){
			var ary = opt.data = [];
			$('option',th).each(function(){
				ary.push({id:$(this).val(),text:$(this).text()});
			});
		}
		return opt;
	}
	function dataloadedEvent(){
		var opt=$(this).data('options'),val=$(this).data('scombo-val').val();
		if(typeof(opt.data)=='string'){//如果data为string类型,则转化成数组对象格式
			var tmp = opt.data.replace(/([^:]*):([^,]*),?/g,function($0,$1,$2){
				return ',{"'+opt.valueField+'":"'+$1.replace(/"/g,'&#34;')+'","'+opt.textField+'":"'+$2.replace(/"/g,'&#34;')+'"}';
			});
			opt.data=$.parseJSON('['+tmp.replace(/^,+|,+$/g,'')+']');
		}
		for(var i=0;i<opt.data.length;i++){//将ID翻译成文本
			if(opt.data[i][opt.valueField]==val){
				$(this).val(opt.data[i][opt.textField]);
				break;
			}
		}
	}
	function validate(target, doit){
		if ($.fn.validatebox){
			var opts = $(target).data('options');
			$(target).validatebox(opts);
			if (doit){
				$(target).validatebox('validate').trigger('mouseleave');
			}
		}
	}
	function makeCenter(div,item){
		div.scrollTop(0);
		if(pos=item.position()){
			div.scrollTop(pos.top-div.height()/2);
		}
	}
	function getVal(exp,defaults){
		try{
			if(typeof(exp)=='function'){
				return parseInt(exp.call(this))||defaults;//如果定义的是FUNCTION,则调用FUNCTION方法获取值,如未返回值或返回的非数字,则使用输入框原宽度
			}
			else{
				return parseInt(exp)||defaults;//如果不是有效数字,使用输入框原宽度
			}
		}
		catch(e){
			return defaults;
		}
	}
	function fillData(div,opt,key){//将内容转化成HTML
		var ary = [];
		for(var i=0;i<opt.data.length;i++){
			if(res=opt.filter(key,opt.data[i])){//根据输入的值对内容进行过滤显示
				var idx = "";
				text = opt.data[i][opt.textField];
				idx = tostr(text.length,3)+tostr(res.position,4)+tostr(res.length,3);
				if(res.length>0){//对匹配出的字串进行着色表示
					for(var j=0;j<res.length;j++){
						text = text.replace(res[j],'<span class=key>'+res[j]+'</span>');
					}
				}
				ary.push({id:opt.data[i][opt.valueField],text:text,idx:idx});
			}
		}
		for(var i=1;i<ary.length;i++){//对数组按idx进行排序
			for(var j=0;j<ary.length-i;j++){
				if(ary[j].idx>ary[j+1].idx){
					var tmp = ary[j];
					ary[j]=ary[j+1];ary[j+1]=tmp;
				}
			}
		}
		var htm = '';
		var max = key?Math.min(opt.maxOptions,ary.length):ary.length;//过滤时只显示设定的最多项目,否则显示全部内容
		
		for(var i=0;i<max;i++){//转化为HTML文本
			if(!opt.multiple||ary[i].id){//多选时,只有VALUE不为空时才显示
				htm+='<div class=scombo-item value="'+ary[i].id+'">'+ary[i].text+'</div>';
			}
		}
		div.html(htm).toggleClass('multiple-combo',opt.multiple).scrollTop(0).show();
		if($('.scombo-item:first',div).text()==$('.scombo-item:first>span',div).text()){
			$('.scombo-item:first',div).addClass('hover');
		}
		if(val=div.data('scombo-box').data('scombo-val').val()){//如果值不为空,则选中对应的选项
			if(opt.multiple){//多选
				$.each(val.split(opt.separator),function(){
					$('.scombo-item[value="'+this+'"]:first').addClass('selected');
				});
			}
			else{//单选
				$('.scombo-item[value="'+val+'"]:first').addClass('selected');
			}
			makeCenter(div,$('.selected:first',div));
		}
		$('.scombo-item',div).bind('mousedown.sombo',function(){//增加选项单击事件
			var target = $(this).parent().data('scombo-box'),th=$(this),opt=target.data('options');
			if(opt.multiple){//多选
				th.toggleClass('selected');
				var ids=[],texts=[];
				$('.selected',div).each(function(){
					ids.push($(this).attr('value'));
					texts.push($(this).text());
				});
				target.data('scombo-val').val(ids.join(opt.separator));
				target.removeData('keypress').val(texts.join(opt.separator)||'');
			}
			else{//单选
				target.data('scombo-val').val(th.attr('value')||'');
				target.val(th.text()||'');
				target.removeData('keypress');//去掉keypress属性,在调用$(document).click()时,不再将文本值赋到VALUE字段中去
				$(document).trigger('mousedown',[true]);
			}
			validate(target,true);
			return false;
		}).mouseover(function(){
			$('.hover',div).removeClass('hover');
			$(this).addClass('hover');
		}).mouseout(function(){
			$(this).removeClass('hover');
		});
	}
	function tostr(num,len){
		var str = '00000000000000000000'+num;
		return str.substr(str.length-len);
	}
})(jQuery);
 
  • 大小: 11.8 KB
分享到:
评论
3 楼 shuaijie506 2014-12-09  
wanghuiyan08 写道
你这个怎么会和easyui 的combogrid 有冲突呢,只要两者在页面中都用的话,结果是都绑定不上,并且scombobox 样式也出不来,数据也没绑定上。如果页面中吧easyui 的 combogrid 去掉,scombobox 就正常了,请问这是怎么回事


不会和easyui的样式冲突的,你按我附件中的例子做就可以了,我们项目中也用了easyui的,这个scombobox只是我针对easyui中combobox速度慢而写了一个改进的版本,本身是与easyui兼容的
2 楼 wanghuiyan08 2014-07-14  
 
1 楼 wanghuiyan08 2014-07-14  
你这个怎么会和easyui 的combogrid 有冲突呢,只要两者在页面中都用的话,结果是都绑定不上,并且scombobox 样式也出不来,数据也没绑定上。如果页面中吧easyui 的 combogrid 去掉,scombobox 就正常了,请问这是怎么回事

相关推荐

    头像选择功能基于jQuery下拉框图片选择示例

    这个“头像选择功能基于jQuery下拉框图片选择示例”提供了一个高效且用户友好的解决方案,使得用户能够方便地从一系列预设的头像中选取自己的代表形象。 首先,我们要理解jQuery库在其中的作用。jQuery是一个广泛...

    jQuery多选下拉框插件

    `jquery.multi-select.js`是基于jQuery的插件,其主要功能是将HTML的`&lt;select multiple&gt;`元素转换为一个带有复选框的可多选下拉框。这个插件的主要特点有: 1. **样式自定义**:通过CSS样式,可以轻松定制多选...

    Jquery Combo下拉框示例

    ComboJS则是基于jQuery构建的,旨在为下拉框添加更多的交互性和功能。 ### 2. ComboJS的核心特性 - **简单易用**:ComboJS通过简单的API接口,允许开发者快速地将普通HTML下拉框转换为具有多种功能的组合框。 - **...

    jquery.multiselect.js多选下拉框选择代码

    这时,jQuery.multiselect.js插件就派上了用场,它提供了一个强大且易于定制的多选下拉框解决方案。 一、jQuery.multiselect.js简介 jQuery.multiselect.js是基于流行的JavaScript库jQuery构建的,它扩展了...

    Jquery各种插件和JQuery Ajax三级联动地区下拉框 & 非Ajax实现三级联动

    标题 "Jquery各种插件和JQuery Ajax三级联动地区下拉框 & 非Ajax实现三级联动" 提供了我们讨论的关键技术点:jQuery、jQuery插件、Ajax以及三级联动地区下拉框的实现。这篇博客(博文链接:...

    jQuery Select下拉框美化表单.zip

    本项目"jQuery Select下拉框美化表单"正是这样一个解决方案,它基于`jquery.selectlist.js`和`jquery-1.9.1.min.js`两个JavaScript文件,旨在为招聘网站等需要展示学历和薪资范围等选项的场景提供更优雅的用户体验。...

    jQuery Select下拉框美化插件.zip

    jQuery Select下拉框美化插件利用jQuery的强大功能,通过简单的API调用就能实现下拉框的美化,减少了开发者编写大量重复代码的工作量。 CSS(层叠样式表)在这里的作用是定义插件的外观和布局。开发者可以通过修改...

    jQuery智能下拉框插件chosenmaster

    ChosenMaster是一款基于jQuery的插件,它将传统的下拉框转化为具有搜索、多选、自定义样式等功能的智能下拉框,显著提升了用户的操作体验。该插件设计简洁,易于集成,并且支持多种浏览器,包括IE7+及现代浏览器。 ...

    jQuery select下拉框菜单选中插件.zip

    本文将详细介绍一个基于jQuery的select下拉框菜单选中插件,旨在帮助你提升用户体验并增强表单的可操作性。 首先,我们需要理解jQuery的核心概念。jQuery是一个轻量级的JavaScript库,它简化了DOM操作、事件处理、...

    基于jquery实现的select美化自定义下拉框样式.zip

    综上所述,"基于jquery实现的select美化自定义下拉框样式.zip"是一个针对前端开发者的学习资源,它提供了使用jQuery来美化和增强select元素的实例。通过学习和实践,开发者可以提升自己的前端技能,为用户提供更加...

    jQuery基于Layui下拉框搜索提示列表代码.zip

    结合Layui,一个轻量级且功能全面的前端UI框架,我们可以实现诸如下拉框搜索提示列表等高级功能。本篇文章将详细介绍如何利用jQuery和Layui实现这一功能,并探讨其背后的原理和技术要点。 首先,`index.html`是整个...

    jQuery插件实现的下拉框美化特效.zip

    这是一款基于jquery.selectlist.js插件实现的下拉框美化特效,简单的jQuery select下拉框美化代码。 js代码 [removed][removed] [removed][removed] [removed] $(function(){ $('select').selectlist({ ...

    jQuery下拉框国家选择代码.zip

    本文将详细介绍如何利用jQuery实现一个国家选择的下拉框,并探讨相关代码的实现细节。 一、jQuery基础 jQuery是一个简洁、高效的JavaScript库,它的主要优点在于简化了DOM操作、事件处理和动画效果。通过使用...

    jQuery+ajax实现三级级联

    在这个“jQuery+ajax实现三级级联”的实例中,我们主要探讨如何利用这两种技术来创建一个能够逐级联动的下拉菜单系统,这在数据筛选和表单填写中十分常见,如地区选择、部门分类等场景。 首先,jQuery是一个轻量级...

    jquery.multiSelect多选下拉框简单实例

    以上就是一个简单的`jquery.multiSelect`多选下拉框实例,你可以根据实际需求进行更深入的定制和扩展,比如集成Ajax动态加载数据、实现搜索过滤等功能。在实际项目中,这个插件能够帮助你创建出更加友好和实用的多选...

    一款jQuery下拉框美化插件.zip

    Dropkick是一款基于jQuery的插件,其主要目标是提供一个简单的方法来替换HTML的`&lt;select&gt;`元素,生成具有现代设计感和流畅交互的下拉菜单。这个插件支持触摸设备,并且可以轻松地与现有的CSS样式和主题集成,从而为...

    简洁的jQuery下拉框城市选择插件.zip

    《基于jQuery的简洁城市选择下拉框插件详解》 在网页开发中,为了提高用户体验,经常需要设计出易于操作的交互元素,如城市选择器。"简洁的jQuery下拉框城市选择插件"就是这样一款实用工具,它利用jQuery的强大功能...

    jQuery扁平化风格下拉框美化插件

    其中,FancySelect是一款基于jQuery的优秀下拉框美化插件,它采用了当前流行的扁平化设计风格,为网页界面增添了一抹现代感。 **一、jQuery库介绍** jQuery是一个轻量级、高性能的JavaScript库,它极大地简化了...

    基于jquery 拖动sliders滑块改变Select下拉框的值.zip

    在本项目中,我们主要探讨如何使用jQuery库来实现一个交互功能:通过拖动滑块(sliders)来改变Select下拉框中的选中值。这个功能常见于各种用户界面设计中,它提供了直观且友好的用户体验,允许用户通过简单的手势...

Global site tag (gtag.js) - Google Analytics