14.3 选择框脚本

优质
小牛编辑
130浏览
2023-12-01

选择框是通过<select>和<option>元素创建的。为了方便与这个控件交互,除了所有表单字段共有的属性和方法外,HTMLSelectElement 类型还提供了下列属性和方法。

  • add(newOption, relOption):向控件中插入新<option>元素,其位置在相关项(relOption)之前。
  • multiple:布尔值,表示是否允许多项选择;等价于HTML 中的multiple 特性。
  • options:控件中所有<option>元素的HTMLCollection。
  • remove(index):移除给定位置的选项。
  • selectedIndex:基于0 的选中项的索引,如果没有选中项,则值为-1。对于支持多选的控件,只保存选中项中第一项的索引。
  • size:选择框中可见的行数;等价于HTML 中的size 特性。

选择框的type 属性不是"select-one",就是"select-multiple",这取决于HTML 代码中有没有multiple 特性。选择框的value 属性由当前选中项决定,相应规则如下。

  • 如果没有选中的项,则选择框的value 属性保存空字符串。
  • 如果有一个选中项,而且该项的value 特性已经在HTML 中指定,则选择框的value 属性等于选中项的value 特性。即使value 特性的值是空字符串,也同样遵循此条规则。
  • 如果有一个选中项,但该项的value 特性在HTML 中未指定,则选择框的value 属性等于该项的文本。
  • 如果有多个选中项,则选择框的value 属性将依据前两条规则取得第一个选中项的值。

以下面的选择框为例:

<select name="location" id="selLocation">
<option value="Sunnyvale, CA">Sunnyvale</option>
<option value="Los Angeles, CA">Los Angeles</option>
<option value="Mountain View, CA">Mountain View</option>
<option value="">China</option>
<option>Australia</option>
</select>

如果用户选择了其中第一项,则选择框的值就是"Sunnyvale, CA"。如果文本为"China"的选项被选中,则选择框的值就是一个空字符串,因为其value 特性是空的。如果选择了最后一项,那么由于<option>中没有指定value 特性,则选择框的值就是"Australia"。
在DOM 中,每个<option>元素都有一个HTMLOptionElement 对象表示。为便于访问数据,HTMLOptionElement 对象添加了下列属性:

  • index:当前选项在options 集合中的索引。
  • label:当前选项的标签;等价于HTML 中的label 特性。
  • selected:布尔值,表示当前选项是否被选中。将这个属性设置为true 可以选中当前选项。
  • text:选项的文本。
  • value:选项的值(等价于HTML 中的value 特性)。

其中大部分属性的目的,都是为了方便对选项数据的访问。虽然也可以使用常规的DOM 功能来访问这些信息,但效率是比较低的,如下面的例子所示:

var selectbox = document.forms[0].elements["location"];
//不推荐
var text = selectbox.options[0].firstChild.nodeValue; //选项的文本
var value = selectbox.options[0].getAttribute("value"); //选项的值

以上代码使用标准DOM 方法,取得了选择框中第一项的文本和值。可以与下面使用选项属性的代码作一比较:

var selectbox = document.forms[0]. elements["location"];
//推荐
var text = selectbox.options[0].text; //选项的文本
var value = selectbox.options[0].value; //选项的值

在操作选项时,我们建议最好是使用特定于选项的属性,因为所有浏览器都支持这些属性。在将表单控件作为DOM 节点的情况下,实际的交互方式则会因浏览器而异。我们不推荐使用标准DOM技术修改<option>元素的文本或者值。
最后,我们还想提醒读者注意一点:选择框的change 事件与其他表单字段的change 事件触发的条件不一样。其他表单字段的change 事件是在值被修改且焦点离开当前字段时触发,而选择框的change 事件只要选中了选项就会触发。

不同浏览器下,选项的value 属性返回什么值也存在差别。但是,在所有浏览器中,value 属性始终等于value 特性。在未指定value 特性的情况下,IE8 会返回空字符串,而IE9+、Safari、Firefox、Chrome 和Opera 则会返回与text 特性相同的值。

14.3.1 选择选项

对于只允许选择一项的选择框,访问选中项的最简单方式,就是使用选择框的selectedIndex 属性,如下面的例子所示:

var selectedOption = selectbox.options[selectbox.selectedIndex];

取得选中项之后,可以像下面这样显示该选项的信息:

var selectedIndex = selectbox.selectedIndex;
var selectedOption = selectbox.options[selectedIndex];
alert("Selected index: " + selectedIndex + "\nSelected text: " +
selectedOption.text + "\nSelected value: " + selectedOption.value);

运行一下
这里,我们通过一个警告框显示了选中项的索引、文本和值。
对于可以选择多项的选择框,selectedfIndex 属性就好像只允许选择一项一样。设置selectedIndex 会导致取消以前的所有选项并选择指定的那一项,而读取selectedIndex 则只会返回选中项中第一项的索引值。
另一种选择选项的方式,就是取得对某一项的引用,然后将其selected 属性设置为true。例如,下面的代码会选中选择框中的第一项:

selectbox.options[0].selected = true;

与selectedIndex 不同,在允许多选的选择框中设置选项的selected 属性,不会取消对其他选中项的选择,因而可以动态选中任意多个项。但是,如果是在单选选择框中,修改某个选项的selected 属性则会取消对其他选项的选择。需要注意的是,将selected 属性设置为false 对单选选择框没有影响。
实际上,selected 属性的作用主要是确定用户选择了选择框中的哪一项。要取得所有选中的项,可以循环遍历选项集合,然后测试每个选项的selected 属性。来看下面的例子。

function getSelectedOptions(selectbox) {
var result = new Array();
var option = null;
for (var i = 0,
len = selectbox.options.length; i < len; i++) {option = selectbox.options[i];if (option.selected) {result.push(option);}
}
return result;
}

运行一下
这个函数可以返回给定选择框中选中项的一个数组。首先,创建一个将包含选中项的数组,然后使用for 循环迭代所有选项,同时检测每一项的selected 属性。如果有选项被选中,则将其添加到result 数组中。最后,返回包含选中项的数组。下面是一个使用getSelectedOptions()函数取得选中项的示例。

var selectbox = document.getElementById("selLocation");
var selectedOptions = getSelectedOptions(selectbox);
var message = "";
for (var i = 0,
len = selectedOptions.length; i < len; i++) {
message += "Selected index: " + selectedOptions[i].index + "\nSelected text: " + selectedOptions[i].text + "\nSelected value: " + selectedOptions[i].value + "\n\n";
}
alert(message);

运行一下
在这个例子中,我们首先从一个选择框中取得了选中项。然后,使用for 循环构建了一条消息,包含所有选中项的信息:每一项的索引、文本和值。这种技术适用于单选和多选选择框。

14.3.2 添加选项

可以使用JavaScript 动态创建选项,并将它们添加到选择框中。添加选项的方式有很多,第一种方式就是使用如下所示的DOM 方法。

var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption);

运行一下
以上代码创建了一个新的<option>元素,然后为它添加了一个文本节点,并设置其value 特性,最后将它添加到了选择框中。添加到选择框之后,用户立即就可以看到新选项。
第二种方式是使用Option 构造函数来创建新选项,这个构造函数是DOM 出现之前就有的,一直遗留到现在。Option 构造函数接受两个参数:文本(text)和值(value);第二个参数可选。
虽然这个构造函数会创建一个Object 的实例,但兼容DOM 的浏览器会返回一个<option>元素。换句话说,在这种情况下,我们仍然可以使用appendChild()将新选项添加到选择框中。来看下面的例子。

var newOption = new Option("Option text", "Option value");
selectbox.appendChild(newOption); //在IE8 及之前版本中有问题

运行一下
这种方式在除IE 之外的浏览器中都可以使用。由于存在bug,IE 在这种方式下不能正确设置新选项的文本。
第三种添加新选项的方式是使用选择框的add()方法。DOM 规定这个方法接受两个参数:要添加的新选项和将位于新选项之后的选项。如果想在列表的最后添加一个选项,应该将第二个参数设置为null。在IE 对add()方法的实现中,第二个参数是可选的,而且如果指定,该参数必须是新选项之后选项的索引。兼容DOM 的浏览器要求必须指定第二个参数,因此要想编写跨浏览器的代码,就不能只传入一个参数。这时候,为第二个参数传入undefined,就可以在所有浏览器中都将新选项插入到列表最后了。来看一个例子。

var newOption = new Option("Option text", "Option value");
selectbox.add(newOption, undefined); //最佳方案

运行一下
在IE 和兼容DOM 的浏览器中,上面的代码都可以正常使用。如果你想将新选项添加到其他位置(不是最后一个),就应该使用标准的DOM技术和insertBefore()方法。

就和在HTML 中一样,此时也不一定要为选项指定值。换句话说,只为Option构造函数传入一个参数(选项的文本)也没有问题。

14.3.3 移除选项

与添加选项类似,移除选项的方式也有很多种。首先,可以使用DOM 的removeChild()方法,为其传入要移除的选项,如下面的例子所示:

selectbox.removeChild(selectbox.options[0]); //移除第一个选项

其次,可以使用选择框的remove()方法。这个方法接受一个参数,即要移除选项的索引,如下面的例子所示:

selectbox.remove(0); //移除第一个选项

最后一种方式,就是将相应选项设置为null。这种方式也是DOM 出现之前浏览器的遗留机制。
例如:

selectbox.options[0] = null; //移除第一个选项

要清除选择框中所有的项,需要迭代所有选项并逐个移除它们,如下面的例子所示:

function clearSelectbox(selectbox) {
for (var i = 0,
len = selectbox.options.length; i < len; i++) {selectbox.remove(i);
}
}

这个函数每次只移除选择框中的第一个选项。由于移除第一个选项后,所有后续选项都会自动向上移动一个位置,因此重复移除第一个选项就可以移除所有选项了。

14.3.4 移动和重排选项

在DOM 标准出现之前,将一个选择框中的选项移动到另一个选择框中是非常麻烦的。整个过程要涉及从第一个选择框中移除选项,然后以相同的文本和值创建新选项,最后再将新选项添加到第二个选择框中。而使用DOM 的appendChild()方法,就可以将第一个选择框中的选项直接移动到第二个选择框中。我们知道,如果为appendChild()方法传入一个文档中已有的元素,那么就会先从该元素的父节点中移除它,再把它添加到指定的位置。下面的代码展示了将第一个选择框中的第一个选项移动到第二个选择框中的过程。

var selectbox1 = document.getElementById("selLocations1");
var selectbox2 = document.getElementById("selLocations2");
selectbox2.appendChild(selectbox1.options[0]);

运行一下
移动选项与移除选项有一个共同之处,即会重置每一个选项的index 属性。
重排选项次序的过程也十分类似,最好的方式仍然是使用DOM 方法。要将选择框中的某一项移动到特定位置,最合适的DOM 方法就是insertBefore();appendChild()方法只适用于将选项添加到选择框的最后。要在选择框中向前移动一个选项的位置,可以使用以下代码:

var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index-1]);

运行一下
以上代码首先选择了要移动的选项,然后将其插入到了排在它前面的选项之前。实际上,第二行代码对除第一个选项之外的其他选项是通用的。类似地,可以使用下列代码将选择框中的选项向后移动一个位置。

var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index+2]);

运行一下
以上代码适用于选择框中的所有选项,包括最后一个选项。

IE7 存在一个页面重绘问题,有时候会导致使用DOM 方法重排的选项不能马上正确显示。