扩展Ext的Combobox实现多选下拉列表

使用过Ext的人都知道,Ext的Combobox只支持单项选择,而项目中我们经常用到多选下拉框,怎么做呢?

很简单,因为Ext给我们提供了继承机制,这也意味着我们可以通过继承Combobox的方式来重写下拉列表的实现,达到多选的目的!

经过查看Combobox的源码我们发现,Combobox的下拉列表是由DataView类来实现的,那么,我们开始大胆的想:我们直接用一个带CheckBox的GridPanal来代替DataView实现可以吗?

OK,当然可以!我自己研究了一下,写了个代码,基本可以实现下拉框多选了:

Ext.form.MultiSelect = Ext.extend(Ext.form.ComboBox, {
	// 使用积极的初始化模式
	lazyInit : false,
	headerText : "EMPTY",
	resetText : "EMPTY",
	sureText : "EMPTY",
	textValue : "",
	maxHeight : 310,
	beforeSelect : null,
	/**
	 * 初始化下拉列表 原来的下拉列表使用DataView类来实现,现在改为使用GridPanel来实现,这样更方便于多选操作
	 */
	initList : function()
	{
		if (!this.list)
		{
			var cls = 'x-combo-list';
			this.list = new Ext.Layer( {
				shadow : this.shadow,
				cls : [ cls, this.listClass ].join(' '),
				constrain : false
			});

			var lw = this.listWidth
					|| Math.max(this.wrap.getWidth(), this.minListWidth);
			this.list.setWidth(lw);
			this.assetHeight = 0;

			if (this.title)
			{
				this.header = this.list.createChild( {
					cls : cls + '-hd',
					html : this.title
				});
				this.assetHeight += this.header.getHeight();
			}

			this.innerList = this.list.createChild( {
				cls : cls + '-inner'
			});
			this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));

			var sm = new Ext.grid.CheckboxSelectionModel();
			var all = this;
			var ht = this.headerText == "EMPTY" ? "选择项目" : this.headerText;
			var rt = this.resetText == "EMPTY" ? "重置" : this.resetText;
			var st = this.sureText == "EMPTY" ? "确定" : this.sureText;
			this.view = new Ext.grid.GridPanel( {
				store : this.store,
				hideHeaders : true,
				applyTo : this.innerList,
				columns : [ sm, {
					header : ht,
					sortable : false,
					dataIndex : this.displayField
				} ],
				viewConfig : {
					forceFit : true
				},
				autoScroll : true,
				width : this.list.getWidth(),
				sm : sm,
				tbar : new Ext.PagingToolbar({ pageSize: this.pageSize, store:this.store}),
				bbar : [ {
					xtype : "button",
					text : rt,
					handler : function()
					{
						all.onReset();
					}
				}, "-", {
					xtype : "button",
					text : st,
					handler : function()
					{
						all.onSure();
					}
				} ],
				iconCls : 'icon-grid'
			});

			// 设置下拉列表的高度,如果超过了最大高度则使用最大高度
			if (this.view.getSize().height > this.maxHeight)
			{
				this.view.setHeight(this.maxHeight);
			}

			// 如果设置了默认值,则在下拉列表中回显
			if (this.value)
			{
				this.setValue(this.value);
			}

			if (this.pageSize)
			{
				/*
				 * var pageBar = new Ext.PagingToolbar({ pageSize: 15, store:
				 * this.view.getStore(), displayInfo: true });
				 * this.view.add(pageBar); this.view.doLayout();
				 */
			}

			if (this.resizable)
			{
				this.resizer = new Ext.Resizable(this.list, {
					pinned : true,
					handles : 'se'
				});
				this.resizer.on('resize', function(r, w, h)
				{
					this.maxHeight = h - this.handleHeight
							- this.list.getFrameWidth('tb') - this.assetHeight;
					this.listWidth = w;
					this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
					this.restrictHeight();
				}, this);
				this[this.pageSize ? 'footer' : 'innerList'].setStyle(
						'margin-bottom', this.handleHeight + 'px');
			}
		}
	},
	/**
	 * 确定选择事件
	 */
	onSure : function()
	{
		var selecteds = this.view.getSelectionModel().getSelections();
		var value = [];
		var all = this;
		var tv = [];
		Ext.each(selecteds, function(rc)
		{
			value.push(rc.data[all.valueField]);
			tv.push(rc.data[all.displayField]);
		});
		this.textValue = tv.join();
		var valueStr = value.join();
		beforeSelect = this.beforeSelect;
		if(typeof beforeSelect == 'function')
		{
			if(!beforeSelect(valueStr))
			{
				this.collapse();
				return;
			}
		}
		this.setValue(valueStr);
		this.value = value.join();
		this.collapse();
	},
	
	getTextValue : function(){
		return this.textValue;
	},
	/**
	 * 重置事件
	 */
	onReset : function()
	{
		this.view.getSelectionModel().clearSelections();
	},
	/**
	 * 给ComboBox设置值 
	 * 设置完全局的值后,再在下拉列表中回显这些值
	 */
	setValue : function(v)
	{
		var text = v;
		var ta = [];
		// 根据值查找出名称,并组装显示
		if (this.valueField && v && ("" + v).length > 0)
		{
			var sv = ("" + v).split(",");
			for ( var i = 0; i < sv.length; i++)
			{
				var r = this.findRecord(this.valueField, sv[i]);
				if (r)
				{
					ta.push(r.data[this.displayField]);
				}
				else if (this.valueNotFoundText !== undefined)
				{
					ta.push(this.valueNotFoundText);
				}
			}
			text = ta.join();
		}
		this.lastSelectionText = ta.join();
		if (this.hiddenField)
		{
			this.hiddenField.value = v;
		}
		this.textValue = text;
		Ext.form.ComboBox.superclass.setValue.call(this, text);
		this.value = v;
		// 在下拉列表中回显设置的值
		if (this.view && v && ("" + v).length > 0)
		{
			var sv = ("" + v).split(",");
			var mv = this.view;
			var sr = [];
			var all = this;
			this.store.each(function(item)
			{
				for ( var i = 0; i < sv.length; i++)
				{
					if (sv[i] == item.data[all.valueField])
					{
						sr.push(item);
						break;
					}
				}
			});
			this.view.getSelectionModel().selectRecords(sr);
		}
	},
	/**
	 * 触发下拉列表展现 这里不使用ComboBox的查询功能,直接展现
	 */
	onTriggerClick : function()
	{
		if (this.disabled)
		{
			return;
		}
		if (this.isExpanded())
		{
			this.collapse();
		}
		else
		{
			this.onFocus( {});
			this.expand();
			this.el.focus();
		}
	}
});


怎么使用呢?看看这个使用的例子吧:











OK,目标达到!细心的朋友会发现,这个多选下拉列表使用的就是GridPanel实现的,而GirdPanel是可以支持分页的,那么我们可不以可以搞分页呢?肯定是可以的,但是经过我试了之后发现,加上分页控件后下拉列表展现变得非常难看,这个问题还是留给朋友们实现吧,呵呵可……

由于注册未满一周,不能上传效果图,大家还是拷贝源码下去自己运行吧……


你可能感兴趣的:(JavaScript)