您的位置:首页 > 其它

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

2012-03-01 14:35 489 查看
使用过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();
}
}
});


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

<html>
<head>
<script type="text/javascript" src="./ext-2.0.2/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="./ext-2.0.2/ext-all.js"></script>
<script type="text/javascript" src="./MultiCombo.js"></script>
<link rel="stylesheet" type="text/css"
href="./ext-2.0.2/resources/css/ext-all.css" />
</head>
<body>
<button onclick="showMenu(this)" id="heare">显示值</button>
<div id="local-states"></div>
</body>
<script>
var store = new Ext.data.SimpleStore({
fields : ['id', 'text'],
data : [['1', '一月'], ['2', '三月'], ['3', '二月'], ['4', '四月'],
['5', '五月'], ['6', '六月'], ['7', '七月'], ['8', '八月'],['9', '九月'], ['10', '十月'], ['11', '十一月'], ['12', '十二月'],['13', '十三月'], ['14', '十四月'], ['15', '十五月']]
});

var combo = new Ext.form.MultiSelect({
id : 'myCombo',
name : 'name',
hiddenName : 'id',
store : store,
emptyText : '请选择...',
mode : 'local',
value : '5,6,7',
triggerAction : 'all',
valueField : 'id',
displayField : 'text',
editable : false,
pageSize : 5,
beforeSelect : function(selectValues){
if(selectValues == '5')
{
return true;
}
else{
Ext.Msg.alert("alert", "Can not!");
return false;
}
},
blankText : '请选择...'
});
combo.render("local-states");

function showMenu(){
alert(combo.getValue());
}
</script>
</html>


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

由于注册未满一周,不能上传效果图,大家还是拷贝源码下去自己运行吧……
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: