jquery combobox && linkage

参考网上已有的combobox,经过改造与完善,特分享一下。

支持一下特性:

1.前台/后台JSON数据

2.下拉条目自定义展示

3.前台过滤下拉条目展示

4.加载过程中友好信息提示

5.与linkage配合,方便构造联动(国家/区域)

6.linkage支持本地缓存

不足之处,

1.使用jquery position插件定位下拉位置,自身实现缺有些瑕疵

2.供职公司要求URL参数定制化太重,JS代码嵌入postdata校验

3.linakge缓存算法太差

.c-list {
	overflow:auto;
	position: absolute;
	z-index: 999999;
	display: none;
	border: 1px solid #CCCCCC;
	background-color: white;
	left:-9999px;
	top:-9999px;
}

.c-list .item {
	display:block;
	overflow: hidden;
	word-break: normal;
	word-wrap: break-word;
	cursor: pointer;
	padding: 2px 0px 2px 5px;
	border-bottom: 1px dashed #CCCCCC;
}

.c-list .item-selected {
	background: #c8e3fc;
}

 

;(function($) {
	
	$.i18n=$.i18n || {};
	$.i18n.combobox={
		NO_DATA:'没有数据',
		LOAD_ERROR:'加载异常',
		LOAD_TEXT:'努力加载中...'
	};
		
	if (!$.browser) {
		var userAgent = navigator.userAgent.toLowerCase();
		// Figure out what browser is being used
		$.browser = {
			version : (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1],
			safari : /webkit/.test(userAgent),
			opera : /opera/.test(userAgent),
			chrome: /chrome/.test(userAgent),
			msie : /msie/.test(userAgent) && !/opera/.test(userAgent),
			mozilla : /mozilla/.test(userAgent)
					&& !/(compatible|webkit)/.test(userAgent)
		};
	}

	/** 高版本浏览器支持 **/
	var ele = document.createElement("input");
	var _support_placeholder = 'placeholder' in ele;

	ele = null;
	
	/**
	 * autocomplete
	 * @constructor
	 */
	$.combobox = function($element, options) {
		
		var self = this,input = $element[0],value=options.value,name=options.name || input.name;
		this.$element = (options.cls ? $element : $element.addClass(options.cls)).removeAttr("name");
		input.value=options.text || '';
		input.autocomplete = 'off';

		// 选中记录索引
		this._selected_=-1;

		// 下拉数据集
		this.records=options.data;
		
		// ajax请求路径
		this.url = options.url;
		
		// ajax请求额外参数
		this.urlParams = options.urlParams;
				
		// URL配置下是否立即请求后台数据 
		this.autoLoad=options.autoLoad;
		
		// ajax请求查找数据记录顶层节点 
		this.dataRoot=options.dataRoot;

		// ajax请求延迟
		this.delay = options.delay;

		// 隐藏值域
		this.valueField = options.valueField;
	
		// 显示域
		this.displayField = options.displayField;

		// 有时候需要获得下拉框数据对应的文本描述
		this.textField=options.textField || (name+"name");

		// 本地查询过滤字段
		this.queryFields = options.queryFields || this.displayField;

		// 下拉条目模板
		this.tpl = "<li class='item' data-index='<% item._index_ === undefined ? i : item._index_ %>'>" + (options.tpl || '<% item.'+this.displayField+'%>') + "</li>";

		/** 浏览器placeholder **/
		var ph = options.placeholder;
		if (ph) {
			_support_placeholder ? $element.attr("placeholder", ph)
					: this.placeholder = ph;
		} else {
			if (!_support_placeholder) {
				ph = $element.attr("placeholder");
				if (ph) {
					this.placeholder = ph;
					$element.removeAttr("placeholder");
				}
			}
		}
		
		// 允许录入文本作为结果
		this.editable=!!options.editable;
		this.editable && $element.addClass("editable");

		// 只读状态 
		this._read_only=false;
		!!options.readOnly || $element.prop("readOnly") ? this.readOnly(true) : false;

		// 隐藏域DOM
		this.$hidden = $("<input type='hidden' ignoreElement='true' name='"+ name + "' value='"+value+"' />").appendTo(input.parentNode);

		// 下拉列表DOM
		this.$list=$('<div class="c-list{cls}"><ul></ul></div>'.replace(/{cls}/,options.listCls ? ' '+ options.listCls: '')).appendTo(document.body);
		options.listWidth && this.$list.width(options.listWidth==='force' ? this.$element.outerWidth() - (this.$list.outerWidth() - this.$list.width()) : options.listWidth);
		options.listHeight && this.$list.height(options.listHeight);

		// 本地数据 : 联动子下拉框 :立即加载AJAX数据
		options.data ? this.json2Html(options.data) : !this.parent && this.autoLoad && this.load();
		
		// 同意接口,设置默认值
		this.reset(value,options.text);

		// 添加事件监听器
		$element.focus(function() {
			
			var sf=self;
			
			// 只读
			if(sf.isReadOnly()){return true;}
			
			var $this=$(this);
		
			// 已聚焦
			if ($this.hasClass("focus")) {return true;};
			
			// 聚焦样式
			$this.removeClass("placeholder").addClass("focus");
			
			// placeholder文本处理(IE6/7/8)
			var ph=sf.placeholder,v=this.value;
			ph && v === ph ? this.value='' : sf.selectRange(0,v.length);

			// 触发事件
			sf.trigger("focus");

			// 下拉DOM已显示
			if(sf.isActive()){return true;}
			
			// 有必要加载远程数据
			!sf.records && sf.load();
			
			// 展示下拉DOOM
			sf.show();

		}).blur(function() {
			
			var sf=self;
			
			// 只读
			if(sf.isReadOnly()){return true;}
		
			// IE doesn't prevent moving focus even with event.preventDefault()
			if (sf._ignore_blur_) {this.focus();sf.selectRange(0, this.value.length);sf._ignore_blur_ = false;return false;}

			// 聚焦样式
			$(this).removeClass("focus");

			// 设值
			sf.value(sf._selected_!=-1 ? sf.records[sf._selected_] : this.value);
			
			// 隐藏下拉
			sf.hide();
			
			// 触发事件
			sf.trigger("blur");
			
			// 校验 
			sf.validate(sf.value());

		}).click(function() {
			
			var sf=self;
			
			// 只读
			if(sf.isReadOnly()){return true;}
			
			// 下拉DOM已显示
			if(sf.isActive()){return true;}
			
			// 有必要加载远程数据
			!sf.records && sf.load();
			
			// 展示下拉DOOM
			sf.show();

		}).keydown(function(e) {
			
			var sf=self;
			
			// 只读
			if(sf.isReadOnly()){return false;}
		
			switch (e.keyCode) {

				case 38: // up
					
					sf.isActive() && sf.focus('prev');
					
					return false;

				case 40: // down
					
					sf.isActive() ? sf.focus('next') : (  !sf.records && sf.load(),sf.show() );

					return false;

				case 9: // tab
					
					return true;
					
				case 13: // enter
				
					sf.isActive() && sf.select() && sf.selectRange(0, this.value.length);

					return false;

				case 27: // escape
					
					// Different browsers have different default behavior for escape
					// Single press can mean undo or clear
					// Double press in IE means clear the whole form
					// e.preventDefault();
					
					sf.isActive() && sf.hide();
					
					return false;

				case 37 : // left
					
					sf.isActive() && sf.hide();
					
					return false;
					
				case 39 : // right
					
					!sf.isActive() && !sf.records && sf.show() && sf.load();
					
					return false;
				case 33 : // page up
					
					sf.isActive() && sf.focus('pageprev');
					
					return false;
				case 34 : // page down
					
					sf.isActive() && sf.focus('pagenext');
					
					return false;
				case 36 : // home
					
					sf.isActive() && sf.focus('first');
					
					return false;
				case 35 : // end
					
					sf.isActive() && sf.focus('last');
					
					return false;
				default:
				
					var that=this;
					
					sf._filter_timer_ && clearTimeout(sf._filter_timer_);
					
					sf._filter_timer_ = setTimeout(function() { sf.filter(that.value); }, sf.delay);
					
					return true;
				}
		}).on("input.combobox",function(){

			// FIREFOX
			var sf=self,that=this;
			
			if(sf.isReadOnly()){return false;}
			
			sf._filter_timer_ && clearTimeout(sf._filter_timer_);
			
			sf._filter_timer_ = setTimeout(function() { sf.filter(that.value); }, sf.delay);
		
		});
		
		// 为表格编辑器做铺垫,必须做判断
		var celleditor=options.celleditor;
		
		// 下拉DOOM事件
		this.$list.on("mouseover.combobox", " > ul > li.item", function(e) {
			
			self.focus($(this));
			
		}).on("click.combobox", " > ul > li.item", function(e) {
			
			self.select($(this)) && self.selectRange(0, self.$element[0].value.length);;
			
		}).mousedown(function(e) {

			// prevent moving focus out of the text field
			e.preventDefault();

			// @IE6/7/8 even prevent default behavior , blur event triggered also
			self._ignore_blur_ = $.browser.msie && (+$.browser.version) < 9;

			// 为表格编辑器做铺垫,必须做判断
			return celleditor ? false : true;
			
		}).scroll(function(e){return false;});

	};

	// 过滤条目
	$.combobox.prototype.filter = function(text) {

		this._selected_ = -1;
		
		// 模糊匹配:改进-左匹配|右匹配
		text=new RegExp(text.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ));

		var r,rs = [],records=this.records,qf=typeof this.queryFields=='string' ? this.queryFields.split(",") : this.queryFields;
		
		// 匹配过滤
		for(var i=0,l=records.length;i<l;i++){
			
			r=records[i];
			r._index_=i;
			
			for(var j=0,s=qf.length;j<s;j++)
				if(text.test(r[qf[j]])){
					rs.push(r);
					break;
				}	
		}
		
		// 执行过滤
		this._filted_ = rs.length != l;
			
		// 重新构建下拉项
		this.json2Html(rs);

		// 重新赋值
		this.records = records;
		
		// 定位下拉DOM位置
		this.position();
		
		// 鼠标悬浮第一条
		this.focus(0);

		return this;
	};
	
	// 下拉DOM展开状态
	$.combobox.prototype.isActive = function() {return this.$list[0].style.display === 'block';};
	
	// 显示下拉DOM
	$.combobox.prototype.show = function(showAllItem) {
		
		// 只读
		if(this.isReadOnly()){return this;}
		
		var isActive=this.isActive();
				
		// 定位下拉DOM位置
		this.position();
		
		// 鼠标悬浮第N条
		this.focus(this._selected_ == -1 ? 0 : this._selected_);

		// 触发事件
		!isActive && this.trigger("active");
		
		return this;
	};
	
	// 隐藏下拉DOM
	$.combobox.prototype.hide = function() {
		
		// 只读
		if(this.isReadOnly()){return this;}

		// 已隐藏
		if(!this.isActive()){return this;}
		
		this.$list[0].style.display = 'none';
		
		// 触发事件
		this.trigger("deactive");
					
		// 如需要重新构造下拉DOM
		var sf=this;
		this._filter_timer_2_  && clearTimeout(this._filter_timer_2_ );
		sf._filted_ ? this._filter_timer_2_ = setTimeout(function(){sf._filted_=false;sf.json2Html(sf.records);},0) : false;
		
		return this;
	
	};
	
	// 下拉DOM位置
	$.combobox.prototype.position=function(){
		
		this.$list[0].style.display='block';
		
		// jQuery position插件
		if ($.ui && $.fn.position) {
			
			this.$list.position( {
				my : "left top",
				at : "left bottom",
				collision : "fit",
				of : this.$element
			});
			
			return this;
		}
			
		// 默认配置,尽量避免 
		var offset = this.$element.offset();
		this.$list.css( {
			top : (offset.top + this.$element[0].offsetHeight) + 'px',
			left : offset.left + 'px'
		});

		return this;
	};

	// 下拉DOM交互信息
	$.combobox.prototype.notice = function(msg) {
		
		var $ul=this.$list.find("> ul");
		
		// 正在加载远程数据 
		if(msg==='load'){
			$ul.html("<li class='notice load'>"+$.i18n.autocomplete.LOAD_TEXT+"</li>");
			return this;
		}
		
		// 无数据
		if(msg==='empty'){
			$ul.html("<li class='notice empty'>"+$.i18n.autocomplete.NO_DATA+"</li>");
			return this;
		}
		
		$ul.html(msg);
		
		return this;
	};
	
	// 远程数据
	$.combobox.prototype.load = function(opts, callback) {
					
		var self = this,cache,cacheKey;
		
		// ajax abort
		this._ajax_request && this._ajax_request.abort();

		typeof opts == 'function' ? (callback=opts,opts={}) : false;
		
		// 深度拷贝&&重载
		opts=$.extend(true,{},this.urlParams,opts);

		// 触发事件
		this.trigger("beforeload",opts);
		
		// 联动框需要缓存
		cacheKey=this.cacheField && opts[this.cacheField];
		
		// 为了配合后台框架必须做的
		if(opts.postdata && typeof opts.postdata == 'object' ){
			
			this.cacheField && opts.searchcondition && opts.searchcondition[this.cacheField] ? cacheKey=opts.searchcondition[this.cacheField] : false;
			
			$.toJSON ? opts.postdata=$.toJSON(opts.postdata) : false;
		}

		// 回调函数
		var ajaxCallback = function(data) {
			
			var sf=self,dataRoot=sf.dataRoot;
			
			data && dataRoot && data[dataRoot] ? data=data[dataRoot] : false;
			
			data= data || [];

			// 缓存写入
			sf.writeCache(cacheKey, data);
			
			// 执行回调函数
			typeof callback == 'function' && callback.call(sf, data);

			sf.json2Html(data);

			// 触发事件 
			sf.trigger("load",data);

			sf.isActive() && sf.show();
		};
						
		// 加载信息
		this.notice('load');
		
		// 如果使用缓存的话
		cache=cacheKey && this.readCache(cacheKey);
		if(cache){ajaxCallback(cache);return this;}

		var url=opts.url || this.url;
		delete opts.url;

		// ajax请求
		this._ajax_request=$.ajax( {
			url : url,
			data : opts,
			method : 'POST',
			dataType : 'json',
			success : ajaxCallback,
			error : function() {ajaxCallback(false);}
		});

		return this;
	};

	// 鼠标悬浮
	$.combobox.prototype.focus = function($item) {

		var cls="item-selected",$ul=this.$list.find("> ul");
		
		// 具体某条
		if($item instanceof jQuery){
		
			!$item.hasClass(cls) && $ul.find(" > li."+cls).removeClass(cls);
		
		}
		
		// 具体某条
		if(typeof $item == 'number'){
			
			$item=$ul.find(" > li.item:eq("+$item+")");
			
			if(!$item.length){return this;}
			
			!$item.hasClass(cls) && $ul.find(" > li."+cls).removeClass(cls);
		}

		// 下一条
		if($item == 'next'){
					
			$item=$ul.find(" > li."+cls).removeClass(cls);
			
			if(!$item.length){return this;}

			$item=$item.next();

			!$item.length ? $item=$ul.find("> li.item:eq(0)") : false;

		}
				
		// 上一条
		if($item == 'prev'){
			
			$item=$ul.find(" > li."+cls).removeClass(cls);
			
			if(!$item.length){return this;}

			$item=$item.prev();

			!$item.length ? $item=$ul.find("> li.item:last-child") : false;

		}
		
		// 第一条
		if($item == 'first'){
			
			$ul.find(" > li."+cls).removeClass(cls);

			$item=$ul.find(" > li.item:eq(0)");

			if(!$item.length){return this;}
		}
		
		// 最后一条
		if($item == 'last'){
			
			$ul.find(" > li."+cls).removeClass(cls);

			$item=$ul.find("> li.item:last-child");

			if(!$item.length){return this;}
		}

		// 上一页
		if($item == 'pageprev'){
			return this.focus("first");
		}
		
		// 下一页
		if($item == 'pagenext'){
			return this.focus("last");
		}
		
		if(!($item instanceof jQuery) || !$item.length){return this;}
		
		$item.addClass(cls);
		
		this.scroll($item);
		
		return this;
		
	};
	
	// 滚动视图
	$.combobox.prototype.scroll = function( $item ) {

		var $list=this.$list,list=$list[0];
		
		if($list.outerHeight() >= $list.prop( "scrollHeight" )){return this;}
		
		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
	
		var borderTop = parseFloat( $.css( list, "borderTopWidth" ) ) || 0,paddingTop = parseFloat( $.css( list, "paddingTop" ) ) || 0;
		var offset = $item.offset().top - $list.offset().top - borderTop - paddingTop,scroll = $list.scrollTop();
		var elementHeight = $list.height(),itemHeight = $item.outerHeight();

		if ( offset < 0 ) {
	
			$list.scrollTop( scroll + offset );
		
		} else {
			if ( offset + itemHeight > elementHeight ) {
				
				//横向滚动条高度
				var scrollbar=0;
				if($list.outerWidth() <= $list.prop( "scrollWidth" )){scrollbar=$.position && $.position.scrollbarWidth && $.position.scrollbarWidth() || 17;}
		
				$list.scrollTop( scroll + offset - elementHeight + itemHeight + scrollbar );	
			
			}
		}

		return this;
	},

	// 鼠标点选
	$.combobox.prototype.select = function($item) {

		// 序号
		var index = typeof $item =='number' ? $item : -1;

		// enter key press
		$item ===  undefined && this.isActive() ? $item = this.$list.find("> ul > li.item-selected") : false;

		// DOM
		$item instanceof jQuery ? index = +$item.data("index") : false;

		var record=this.records[index];

		this._selected_ !== index && this.trigger("beforeselect",record);

		this.$hidden[0].value = record[this.valueField];
		
		this.$element[0].value = record[this.displayField];

		this._selected_ !== index  && this.trigger("select",record);
		
		this._selected_ = index;
		
		this.hide();

		return this;
	};

	// MY GOD DOM
	$.combobox.prototype.selectRange = function(start, end) {
		
		var input = this.$element[0];
		
		if (input.setSelectionRange) {
		
			input.focus();
			input.setSelectionRange(start, end);
		
		} else if (input.createTextRange) {
			
			var range = input.createTextRange();
			
			range.collapse(true);
			
			range.moveEnd('character', end);
			
			range.moveStart('character', start);
		
			range.select();
		
		}
		
		return this;
	};

	// 查找记录
	$.combobox.prototype.find = function(key, value) {
		
		var records=this.records || [],l = records.length;
		
		// 根据索引查找
		if (typeof key == 'number') 
			return l > key ? records[key] : null;

		// 根据属性查找,如name:'tom'
		while (l--)
			if (records[l][key] == value)
				return records[l];

		return null;
	};

	// 查找记录索引
	$.combobox.prototype.indexOf = function(key, value) {
		
		// 一个参数
		arguments.length == 1 && (value=key,key=this.valueField);

		// 参数为记录
		typeof value == 'object' ? value = value[this.valueField] : false;
		
		var records=this.records || [],l = records.length;
		
		while(l--)
			if(records[l][key]== value)
				return l;
		
		return -1;
	};

	// 缓存读取 
	$.combobox.prototype.readCache = function(cacheKey) {
		
		this._cache_data=this._cache_data || {};
		
		if(this._use_cache && cacheKey){
			
			var cache=this._cache_data[cacheKey];
			
			// 最近经常使用
			cache ? cache.count=(cache.count || 0) + 1 : false;
			
			return cache ? cache.data : null;
		}
		
		return null;
		
	};

	// 缓存写入
	$.combobox.prototype.writeCache = function(cacheKey, data) {
		
		this._cache_data=this._cache_data || {};
		
		if(this._use_cache && cacheKey && data){
			
			// 清空缓存,应该搞个算法,最近很少使用
			if(this._cache_length > this._cache_size){
				
				this._cache_data={};
				
				this._cache_length=0;
			
			}
			
			this._cache_length++;
			this._cache_data[cacheKey]={data:data,count:0};
		}
		
		return this;
	
	};

	// JSON数据转化为HTML字符串
	$.combobox.prototype.json2Html = function(json, template) {
		
		var tplEngine = function(tpl, data) {
		    var reg = /<%([^%>]+)?%>/g, 
		        regOut = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, 
		        code = 'var r=[];\n', 
		        cursor = 0;
		 
		    var add = function(line, js) {
		        js? (code += line.match(regOut) ? line + '\n' : 'r.push(' + line + ');\n') :
		            (code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
		        return add;
		    }
		    while(match = reg.exec(tpl)) {
		        add(tpl.slice(cursor, match.index))(match[1], true);
		        cursor = match.index + match[0].length;
		    }
		    add(tpl.substr(cursor, tpl.length - cursor));
		    code += 'return r.join("");';
		    return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
		};

		var code='<% for(var i=0,l=this && this.length || 0;i<l;i++){var item=this[i]; %>'+
				 (template || this.tpl)+
				 '<% } %>';

		this.records = json || [] ;
		
		this.notice(!json || json.length===0 ? 'empty' : tplEngine(code,json || []));

		return this;
	};
	
	// 校验
	$.combobox.prototype.validate=function(){return $.validate ? $.validate(this.$element) : true;};
	
	// 只读状态
	$.combobox.prototype.isReadOnly=function(){return this._read_only===true;};

	// 设置只读状态
	$.combobox.prototype.readOnly = function(readOnly) {
		
		readOnly=!!readOnly;
		
		this._read_only=readOnly;
	
		this.$element[readOnly ? "addClass" : "removeClass"]("readOnly").prop("readOnly",readOnly);
		
		return this;
	};
	
	// 文本框文本
	$.combobox.prototype.text=function(){
		
		var text=this.$element[0].value;
		
		return this.placeholder && text===this.placeholder ? "" : text;
	};
	
	// 值处理
	$.combobox.prototype.value = function(value,text) {

		// getter method
		if (value === undefined) {return this.$hidden[0].value;}

		// 类似于清空效果
		value===null ? value='' : false;

		// 必须ajax加载后设值
		if(!this.records && this.url && value){
					
			var self=this;

			this.one("load",function(){self.value(value,text);}).load();
			
			return this;
		}

		var oldValue = this.value();
		
		// 参数为数据记录或者普通字符串数据
		var index = this.indexOf(value);
		
		var record = index != -1 ? this.records[index] : null;
		
		value = record ? record[this.valueField] : ( this.editable ? value : '' );

		text = record ? record[this.displayField] : ( this.editable && text || value );
		
		this._selected_ = index;
		
		this.$hidden[0].value = value;

		var ph=this.placeholder;
		
		// placeholder样式
		this.$element[0].value = ph && text==="" ? ph : text;
		ph && this.$element[(text ? "remove" : "add") + "Class"]("placeholder");
				
		var newValue = this.value();
		
		// 触发事件
		oldValue != newValue && this.trigger("select",record);

		// 触发事件
		oldValue != newValue && this.trigger("change",newValue,oldValue);

		return this;
	};

	// 值重置
	$.combobox.prototype.reset = function(value,text) {

		this._default_value= value != null && typeof value == 'object' ? value[this.valueField] : value;

		// 字符串化
		this._default_value = this._default_value === undefined ? '' : ''+this._default_value;
		
		this.value(value,text);

		return this;
	};

	$.combobox.prototype.trigger = function(event) {
		var params = [ this];
		for ( var i = 1, l = arguments.length; i < l; i++) {
			params[i] = arguments[i];
		}
		
		var type=event.toUpperCase();
		event=new jQuery.Event(type, type+"."+this.widget );
		this.$element.triggerHandler(event, params);
	
		return event;
	};

	$.combobox.prototype.on = function(event, handler) {
		this.$element.on(event.toUpperCase() + "." + this.widget, handler);
		return this;
	};
	
	$.combobox.prototype.one = function(event, handler) {
		this.$element.one(event.toUpperCase() + "." + this.widget, handler);
		return this;
	};

	$.combobox.prototype.off = function(event, handler) {
		this.$element.off(((event && event.toUpperCase()) || '') + "." + this.widget, handler);
		return this;
	};

	$.combobox.prototype.destroy=function(keep){
		
		this.$list.off(".combobox").remove();
		
		this.$element.off(".combobox").removeData();

		this.off();
		
		var name=this.$hidden[0].name;
		
		this.$hidden.remove();
		
		!!keep ? this.$element[0].name=name : this.$element.remove();
		
	};
		
	// 添加子联动节点 
	$.combobox.prototype.addChild = function(child) {
		this.children=this.children || [];
		
		for(var i=0,l=this.children.length;i<l;i++)
			if(this.children[i]===child)
				break;

		l==0 || i===l ? (child.parent=this,this.children.push(child)) : false;
		return this;
	};
	
	// 删除子联动节点
	$.combobox.prototype.removeChild = function(child) {
		this.children=this.children || [];
		for(var i=0,l=this.children.length;i<l;i++)
			if(this.children[i]===child)
				break;
		i!==l ? (child.parent=null,this.children.splice(i,1)) : false;
		return this;
	};
	
	// 是否包含联动节点
	$.combobox.prototype.hasChild = function() {
		return this.children && this.children.length > 0;
	};
	
	$.combobox.prototype.widget = 'combobox';
	
	$.fn.combobox = function(options) {
		
		var f=null,fields=[];

		for(var i=0,l=this.length;i<l;i++){
				f=$.data(this[i], "widget");
				!f ? (f=new $.combobox(this.eq(i), $.extend( {}, $.fn.combobox.defaults, options)),$.data(this[i], "widget", f)) : false;
				fields[i]=f;
		}

		return l===1 ? fields[0] : fields;
	};
	
	/**
	 * Default options for combobox plugin
	 */
	$.fn.combobox.defaults = {
		
		data:false,
		
		/** 远程请求配置 **/
		url : '',
		
		urlParams : {},
		
		autoLoad:false,
		
		dataRoot:'dataroot',
		
		/** 前后台交互属性 **/
		name : '',

		/** 添加class到input **/
		cls : '',

		/** 添加class到下拉列表 **/
		listCls : '',

		/** 下拉列表高度,默认auto **/
		listHeight:'',
		
		/** 下拉列表宽度,默认与文本框相同 **/
		listWidth:'force',

		/** 定时器间隔 **/
		delay : 50,

		/** 下拉条目模板 **/
		tpl : '',

		/** 显示域 **/
		displayField : 'name',

		/** 值域 **/
		valueField : 'code',
		
		textField:'',

		/** 查询字段 **/
		queryFields : '',

		/** /** 默认值,待定? **/
		value : '',

		placeholder:'',
		
		/** 不要修改此处 **/
		celleditor:false
	};
	
	
	/**
	 * linkage
	 * @constructor
	 */
	$.linkage = function($element, options) {
		
		var self=this;

		/** 联动节点 **/
		if(options.parent){

			options.readOnly=true;
			
			options.parent.addChild(this);
			
			this.parentField=options.parentField || options.name || $element[0].name;

			/** 使用本地缓存 **/
			this._use_cache = !!options.useCache;
			if (this._use_cache) {
				
				/** 缓存KEY **/
				this.cacheField=options.cacheField || this.parentField;
				
				this._cache_data = {};
				this._cache_length = 0;
				this._cache_size = options.cacheSize;
				
			}
			
			if(!this.parent._linkage_listener){
				
				this.parent._linkage_listener=true;
				
				/** 当前节点选择,加载下级节点数据 **/
				this.parent.on("select",function(e,f,r){
					var chs=f.children || [],newValue=r && r[f.valueField] || null;
					
					/** 为了配合后台框架,没办法 **/
					var data={postdata:{searchcondition:{}}};
					data[self.parentField]=newValue;
					data.postdata.searchcondition[self.parentField]=newValue;
		
					for(var i=0,l=chs.length;i<l;i++){
						
						chs[i].value(null);
						
						chs[i].readOnly(true);
					
						newValue && chs[i].load(data,function(){this.readOnly(false);});
					}
					
				}).on("blur",function(e,f){
					var chs=f.children || [],value=f.value();
					if(value===''){
						for(var i=0,l=chs.length;i<l;i++){
						
							chs[i].value(null);
							
							chs[i].readOnly(true);
						}
					}

				}).on("load",function(e,f,args){
					var reset=function(chs){
						chs=chs || [];
						for(var i=0,l=chs.length;i<l;i++){
							chs[i].value(null);
							chs[i].readOnly(true);
							reset(chs[i].children);
						}
					}
					reset(f.children);
				});
			}
		}

		$.combobox.call(this,$element,options);
		
	};
	
	$.extend($.linkage.prototype,$.combobox.prototype);
	
	$.linkage.prototype.widget = 'linkage';
	
	$.fn.linkage = function(options) {
		
		var f=null,fields=[];

		for(var i=0,l=this.length;i<l;i++){
				f=$.data(this[i], "widget");
				!f ? (f=new $.linkage(this.eq(i), $.extend( {}, $.fn.linkage.defaults, options)),$.data(this[i], "widget", f)) : false;
				fields[i]=f;
		}

		return l===1 ? fields[0] : fields;
	};
	
	/**
	 * Default options for linkage plugin
	 */
	$.fn.linkage.defaults=$.extend({
		useCache:true,		
		cacheField:'',
		cacheSize : 10,
		parent:false,
		parentField:'parent'
	},$.fn.combobox.defaults);
	

})(jQuery);
 
调用方式很简单:
<input type='text' id='local' />
<input type='text' id='remote' />

<script>

$("#local").combobox({data:[{name:'男',code:'1'},{name:'女',code:'2'}]});

//后台返回JSON数据:result:{data:[{name:'男',code:'1'},{name:'女',code:'2'}]}
$("#remote").combobox({url:'getSexData.action',dataRoot:'result'});

</script>
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值