网上这样的控件不少,有很多实现方法,其中不少的很巧妙。
例如:在文本框(HTML INPUT)后,添加一个隐藏层,隐藏层上放一个下拉列表,存储了所有可能的元素,每次文本框触发onpropertychange事件,就是对隐藏层上下拉列表数据的过滤显示。而选择下拉列表,则对文本框进行赋值......然后我们可以通过一些CSS技巧,将它的外观调整成一个可输入可联想下拉列表的模样。
当然,本文并不打算对上述实现方式进行讨论,而是将EXT中一些实用的控件,“便宜地”添加到我们的项目中来(EXT版本1.1.1)。是的,我强调的是“便宜”!
EXT上有一种控件ComboBox,就包含了这样的特性,而我们要使用它,标准的做法是:
1. 首先,你需要将ext-1.1.1(如果你要使用它的样式,那么里面的resource是必须的——样式定义,以及它所依赖的图片都放在里面)添加到项目中来,在需要使用ComboBox的页面添加JS(必须)和CSS引用路径:
< script type ="text/javascript" src ="../js/ext-1.1.1/adapter/ext/ext-base.js" ></ script >
< script type ="text/javascript" src ="../js/ext-1.1.1/ext-all.js" ></ script >
注意路径哦!
2. 你需要一个载体,EXT就是这样,布局需要document.body,Grid需要<div>,而ComboBox则需要一个<input type="text">:

3. 新建一个JS文件,其间包括对存储结构的定义和ComboBox属性的定义:
Ext.QuickTips.init();
var data =
[
[ ' 1 ' , ' Lislie ' , ' D005 ' , ' male ' ],
[ ' 2 ' , ' Merry ' , ' D004 ' , ' female ' ],
[ ' 3 ' , ' Edison ' , ' D003 ' , ' male ' ],
[ ' 4 ' , ' Mark ' , ' D002 ' , ' male ' ],
[ ' 5 ' , ' Leeon ' , ' D001 ' , ' male ' ]
];
// 格式化数据
var ds = new Ext.data.Store({
proxy: new Ext.data.MemoryProxy(data), // 数据源
reader: new Ext.data.ArrayReader({}, [ // 如何解析
{name: ' id ' },
{name: ' name ' },
{name: ' depno ' },
{name: ' sex ' }
])
});
ds.load();
var storeList = new Ext.form.ComboBox({
store: ds,
valueField: ' id ' , // option.value
typeAhead: true ,
displayField: ' name ' , // option.text
triggerAction: ' all ' ,
emptyText: ' Select a store... ' ,
mode: ' local ' ,
selectOnFocus: true ,
width: 135
});
storeList.applyTo( ' local1 ' );
});
上面的数据来源是一个写死的2维数组。同样的道理,你的数据源可以来自一个链接——请求一个页面,而该页面的Response返回一个符合Json格式的字符串(EXT里面最常用的存储方式是JSON),那么Ext.data.Store的定义就变成了这样:
proxy: new Ext.data.ScriptTagProxy({ url: ' http://localhost:17319/KBS/Grid/EditString.aspx ' }), // 数据源
reader: new Ext.data.JsonReader({ // 解析格式
totalProperty : ' totalCount ' , // 用于分页
root : ' root ' ,
id : ' id '
},
[
{name: ' id ' },
{name: ' name ' },
{name: ' depno ' },
{name: ' sex ' }
])
});
如此,需要请求页面返回的String符合这样的格式,例如:









网上有不少将DataTable或Model转JSON的工具类,当然也也可以自己写,反射+字符串的拼接。
3. 最后,将这个JS引用到页面上。那么一个可输入可联想的控件便出来了。这里有一个小的BUG(暂且用这个词吧),ComboBox终究是放在一个<input>上。
在前台,你可以通过storeList.getValue()获取当前的选中项的option.value(如果是手动输入的项,而非经过联想选中的项,storeList.getValue()得到的是'',你只能获取到storeList.getRawValue()即<input>的value。需要在点击保存按钮时,在onclick事件中将两者的值设置为一致:“οnclick='javascript:storeList.setValue(storeList.getRawValue);'”)。
而在后台,你无法像操作<select>一样,获取它的option.value,而只得到它的text。也只能操作这个Text了。
总结:如果你的数据库操作放在前台,那么你完全可以将ComboBox当成一个<select>(功能更强大,允许你输入不存在的项)。如果你的数据库操作放在后台,那么,你只能操作它的Text了,而所谓的可联想、可输入下拉列表,其实是一个糊弄人的文本框而已。
------------------------------------------------------------------------------
老实说,上面的实现过程还是很麻烦,这里有一个很简单的实现方式——其实EXT研发小组已经替我们完成了这一步,是的,仔细看API,你会发现:
你可以将一个带数据的<select>轻松的转化为ComboBox,哪怕它是asp的控件<asp:DropdownList>。而这个转化过程,就是ComboBox的一行属性:
Ext.onReady( function (){
Ext.QuickTips.init();
storeList = new Ext.form.ComboBox({
typeAhead: true ,
triggerAction: ' all ' ,
emptyText: ' Select a store... ' ,
mode: ' local ' ,
selectOnFocus: true ,
transform: ' AList ' , // 将已存在select(通过id)直接转ComboBox
width: 135
});
})
缺陷是,手动输入的不存在的项,在后台无法取到。
两种方式区别:由于载体的不同,一个<input>,一个<select>,导致在后台,我们取值方法和取的内容也不同。虽然说,两者在外观和功能上一模一样,但后者才能真正算可输入可联想的下拉列表吧!
附(效果图):