HTML 只提供了文本框和下拉列表框,没有提供 ComboBox 控件。虽然可以通过并排显示文本框和下拉列表框,并以脚本控制其关联的方法实现,但显示效果的确不理想。于是大家都想办法解决。综合了一下,现有的实现方法有两种思路:
1、用文本框加 Img 或 div 的方法,在点击时通过脚本控制某个层的显示状态。优点是可定义非常好的显示效果,也可实现非常复杂的功能。比如和数据库关联,显示树型的结构或多列的记录结构等。缺点是太复杂,不容易使用控制。
2、用文本框加下拉列表框实现,通过CSS将两个控件组合成 ComboBox 的外观,再用脚本实现联动。优点是简单易用,缺点是只能显示单行的列表,不能实现复杂的功能。
考虑到常用的功能,还是用第 2 种方法较为方便。在网上找了一些,虽然实现了这个效果,但使用起来比较麻烦。比如页面上有很多个这样控件时,工作量就太大了,而且维护修改起来不太方便。还是自己动手吧。
如果网站上有十个网页需要用到 ComboBox 控件,每个页面上又同时有十个存在,我想总不能一个一个的写一百遍吧?而且每一个的内容、宽度、ID都不同,即使将代码复制过去还需要大量的修改,这样的工作量可想而知。所以,这里的关键是如何将其组件化,以使在使用的时候最方便化,并且在修改时只修改组件即可。
那么如何组件化呢?自然而然想到了 HTC !
先来看看最终效果:
实现思路:ComboBox 控件的主要部分还是文本框,下拉列表框只是提供一个侯选的列表。所以我们以文本框为主,由 HTC 负责为其添加下拉列表框。使用时只要为文本框指定一个 combobox 的样式,再多写一个以逗号分隔的字符串作为下拉列表的内容就行了。如:
这个 combobox 样式定义为:
behavior : url(combobox.htc) ;
}
combobox.htc 内容如下:
< public:attach event ="ondocumentready" onevent ="init()" />
< public:property name ="items" />
< script type ="text/javascript" >
function init(){
if (items != null ){
items = items.replace( / ( ^ s * ) | (s * $) / g, "" );
if (items != '' ) {
var arritem = items.split( ' , ' );
var selcon = document.createElement( ' select ' );
selcon.options.add(document.createElement( " option " ));
for ( var i = 0 ;i < arritem.length;i ++ ){
var oOption = document.createElement( " option " );
var text = arritem[i];
if (text != '' )text = text.replace( / ( ^ s * ) | (s * $) / g, "" );
oOption.text = text;
oOption.value = text;
selcon.options.add(oOption);
}
selcon.style.position = ' absolute ' ;
selcon.style.width = element.clientWidth + 20 + ' px ' ;
selcon.style.clip = ' rect(auto auto auto ' + element.clientWidth + ' px) ' ;
selcon.style.marginTop = ' 1px ' ;
selcon.onchange = function (){
element.value = this .value;
element.select();
element.focus();
}
var parent = element.parentNode;
parent.insertBefore(selcon,element);
}
}
}
</ script >
</ public:component >
所有需要使用 ComboBox 的地方,使用普通的文本框即可,只要定义样式为 combobox,并且 items 属性不为空,它就会显示为下拉框。是不是很好用呀?! 而且再为它定义方法,就很容易实现列表的添加修改和删除功能了。
不过不要高兴的太早,HTC虽然是个好东西,但目前只有 IE 支持,也就是说,在非 IE 浏览器里显示的还是一个正常的文本框。
即然如此,那就用另外一种方法来解决兼容性问题。将下面的函数 ComboBox 在 window.onload 里调用即可,它会查找所有样式为 combobox 的文本框,并为它们添加下拉列表
var inputs = document.getElementsByTagName( ' input ' );
var comboboxs = new Array;
for ( var i = 0 ;i < inputs.length;i ++ ){
var item = inputs[i];
if (item.type == ' text ' && item.className == ' combobox ' )
comboboxs[comboboxs.length] = item;
}
if (comboboxs.length > 0 ){
for ( var i = 0 ;i < comboboxs.length;i ++ ){
var combobox = comboboxs[i];
var items = combobox.getAttribute( ' items ' );
if (items != null ) {
items = items.replace( / ( ^ s * ) | (s * $) / g, "" );
if (items != '' ) {
var arritem = items.split( ' , ' );
var selcon = document.createElement( ' select ' );
selcon.options.add(document.createElement( " option " ));
for ( var j = 0 ; j < arritem.length; j ++ ) {
var oOption = document.createElement( " option " );
var text = arritem[j];
if (text != '' )
text = text.replace( / ( ^ s * ) | (s * $) / g, "" );
oOption.text = text;
oOption.value = text;
selcon.options.add(oOption);
}
selcon.style.position = ' absolute ' ;
selcon.style.width = combobox.clientWidth + 20 + ' px ' ;
selcon.style.clip = ' rect(auto auto auto ' + combobox.clientWidth + ' px) ' ;
if (document.all && window.external)selcon.style.marginTop = ' 1px ' ;
selcon.onchange = function (){
var input = this .nextSibling;
input.value = this .value;
input.select();
input.focus();
}
var parent = combobox.parentNode;
parent.insertBefore(selcon, combobox);
}
}
}
}
};
实现过程:
怎样将文本框和下拉列表组合?
从理论上讲,只要将文本框和下拉列表框“紧紧的”并排挤在一起,并将下拉列表框的宽度减小到只留下一个下拉箭头,就和 ComboBox 的外观相同了。
但是,在 IE 中,下拉列表框的宽度减小了,点击下拉箭头展开的列表的宽度也跟着减小了,看不到内容了;而在非 IE 中,下拉列表框的宽度小于下拉箭头的宽度时就会隐藏下拉箭头,也不是我们想要的效果,所以不能用这种方法。
好在 CSS 中提供了 clip 的样式,它可以设置对象的可视区域,而且可视区域外的部分是透明的。这样就符合我们的要求了:将下拉列表框除下拉箭头外都隐藏起来!
但当把 clip 样式赋给下拉列表框后,却没有任何效果!原来, clip 样式只会在 position 样式的为 absolute ,即对象为绝对定位方式时才会起作用。
当赋予下拉列表框绝对定位样式后,需要把它的代码放在文本框代码之前,这样两个控件就会重合,再把下拉列表框的宽度定为文本框加上下拉箭头的宽度,再将文本框宽度的部分隐藏,就完美组合成了 ComboBox 控件。
清楚了组合方法,代码就容易写了。动态创建下拉列表框,插入文本框前面,再设置样式,添加事件以实现两个控件关联。上面两种方法的基本代码相同,都是这一过程。
HTC 方法在 IE6、IE7下测试通过;没有 IE 5.5 无法测试,IE 5.5 以下版本不支持 HTC
函数方法在 IE6、IE7、Opera 9.2、Firefox 1.5、Firefox 2.0下测试通过。