打印

SD9030: 为 SELECT 对象增加或删除选项的方法在各浏览器中的支持情况不同

作者:王军

标准参考

DOM 2 HTML 中分别定义了 HTMLSelectElement、HTMLOptionsCollection 和 HTMLOptionElement 接口,它们分别定义了若干属性和方法来获知或操作 SELECT 及 OPTION 元素。

HTMLSelectElement 接口定义了以下属性及方法:

  • length: 获取 SELECT 元素中 OPTION 的数量;
  • options: 获取 SELECT 包含的 OPTION 元素集合,其返回值类型为 HTMLOptionsCollection;
  • add(element, before): 向 SELECT 中添加一个 OPTION,参数 element 指定要添加的 OPTION 对象,before 指定了插入到哪个 OPTION 之前,如果值为 'null',则插入 SELECT 尾部;
  • remove(index): 从 SELECT 中删除一个 OPTION,参数 index 指定了要删除的 OPTION 索引。

HTMLOptionsCollection 接口是一个 OPTION 节点列表,可以通过索引或某个 OPTION 节点的 name 或 id 属性访问该 OPTION。 它定义了 'length' 属性,用来获取当前 OPTION 节点列表的长度,作用同 HTMLSelectElement 的 'length' 属性。

关于 HTMLSelectElement、HTMLOptionsCollection 和 HTMLOptionElement 接口的详细信息,请参考 DOM 2 HTML: Interface HTMLSelectElementInterface HTMLOptionsCollection (introduced in DOM Level 2)Interface HTMLOptionElement

问题描述

各浏览器对标准的支持有差异,并且他们实现了非标准的添加和删除 OPTION 元素的方法,在使用这些方法时,可能造成兼容性问题。

造成的影响

如果使用了存在兼容性问题的添加或删除 OPTION 元素的方法,将可能导致脚本异常,功能不可用。

受影响的浏览器

所有浏览器

问题分析

除了标准提到的方法外,各浏览还实现了另外几种添加、删除 OPTION 元素的方法,各浏览器对这些方法的支持程度不一致。

非标准的添加 OPTION 的方法:

  • select.add(option):SELECT 对象的方法,直接插入参数 option 到尾部;
  • select.add(option, index):在指定的 OPTION 列表索引 index 之前插入参数 option;
  • options.add(option, before):OPTION 节点列表(实现 HTMLOptionsCollection)的方法,效果同 HTMLSelectElement.add;
  • options.add(option):同第一个方法;
  • options.add(option, index):同第二个方法;
  • options[index] = option:直接在 OPTION 节点列表上添加元素。

非标准的删除 OPTION 的方法:

  • select.remove(option):SELECT 对象的方法,删除参数指定的 OPTION 对象;
  • options.remove(index):OPTION 节点列表的方法,同 HTMLSelectElement.remove;
  • options.remove(option):同第一个方法;
  • options[index] = null:直接在 OPTION 节点列表上设置元素为 null。

分析以下代码:

<style type="text/css">select {height:100px;}</style>
<table>
  <tbody>
    <tr>
      <td>
        <select id="s1" multiple="multiple">
          <option value="1">111</option>
          <option value="2">222</option>
        </select>
      </td>
      <td>
        <select id="s2" multiple="multiple">
          <option value="1">111</option>
        </select>
      </td>
      <td>
        <select id="s3" multiple="multiple">
          <option value="1">111</option>
          <option value="2">222</option>
        </select>
      </td>
      <td>
        <select id="s4" multiple="multiple">
          <option value="1">111</option>
        </select>
      </td>
      <td>
        <select id="s5" multiple="multiple">
          <option value="1">111</option>
        </select>
      </td>
    </tr>
    <tr>
      <td><button type="button" onclick="remove(1);">select.remove(index)</button></td>
      <td><button type="button" onclick="remove(2);">select.remove(option)</button></td>
      <td><button type="button" onclick="remove(3);">options.remove(index)</button></td>
      <td><button type="button" onclick="remove(4);">options.remove(option)</button></td>
      <td><button type="button" onclick="remove(5);">options[index] = null</button></td>
    </tr>
  </tbody>
</table>

<div style="border:2px solid;padding:3px;width:800px;" id="info"></div>

<script type="text/javascript">
  function $(id){return document.getElementById(id);}
  function newOpt(text, val){return new Option(text, val);} 1
  function info(method, msg){$("info").innerHTML += "<strong>" + method + "</strong> : " + msg + "<br />";}

  //创建n个 OPTION 对象
  var opt1 = newOpt("select.add(option, null)", 2),
    opt2 = newOpt("select.add(option)", 2),
    opt3 = newOpt("options.add(option, null)", 2),
    opt4 = newOpt("options.add(option)", 2),
    opt5 = newOpt("options[index] = option", 2),
    opt6 = newOpt("select.add(option, option)", 2),
    opt7 = newOpt("select.add(option, index)", 2),
    opt8 = newOpt("options.add(option, option)", 2),
    opt9 = newOpt("options.add(option, index)", 2),
    s1 = $("s1"),
    s2 = $("s2"),
    s3 = $("s3"),
    s4 = $("s4"),
    s5 = $("s5");

  //使用n种方法添加 OPTION 到 SELECT 中
  try { s1.add(opt1, null); } catch(e) { info("select.add(option, null)", e) }
  try { s2.add(opt2); } catch(e) { info("select.add(option)", e) }
  try { s3.options.add(opt3, null); } catch(e) { info("options.add(option, null)", e) }
  try { s4.options.add(opt4); } catch(e) { info("options.add(option)", e) }
  try { s5.options[1] = opt5; } catch(e) { info("options[index] = option", e) }

  try { s1.add(opt6, s1.lastChild); } catch(e) { info("select.add(option, option)", e) }
  try { s1.add(opt7, 1); } catch(e) { info("select.add(option, index)", e) }
  try { s3.options.add(opt8, s3.lastChild); } catch(e) { info("options.add(option, option)", e) }
  try { s3.options.add(opt9, 1); } catch(e) { info("options.add(option, index)", e) }

  function remove(type){
    var method = "";
    try {
      switch(type) {
        case 1 :
          method = "s1.remove(0)";
          break;
        case 2 :
          method = "s2.remove(s2.firstChild)";
          break;
        case 3 :
          method = "s3.options.remove(0)";
          break;
        case 4 :
          method = "s4.options.remove(s4.firstChild)";
          break;
        case 5 :
          method = "s5.options[1] = null";
          break;
      }
      eval(method);
    } catch (e) {
      info(method, e);
    }
  }
</script>

上述代码首先使用了标准及非标准方法向各 SELECT 元素中添加了 OPTION,然后点击各按钮使用各种删除方法删除 OPTION, 根据抛出的异常信息,我们可以辨别出哪些方法在浏览器中不支持,汇总测试结果如下表:2

type method IE6 IE7 IE8(Q) IE8(S) Opera Firefox Chrome Safari
add OPTION select.add(option, null) N Y Y Y
select.add(option, option) N Y Y Y
select.add(option, index) Y Y N N3
select.add(option) Y Y N Y
options.add(option, null) N Y N4 N4
options.add(option, option) N Y N N
options.add(option, index) Y Y Y Y
options.add(option) Y Y Y Y
options[index] = option Y Y Y Y
remove OPTION select.remove(index) Y Y Y Y
select.remove(option) Y Y Y Y
options.remove(index) Y Y N Y
options.remove(option) Y Y N Y
options[index] = null Y Y Y Y

注1:这里使用 new Option(text, value) 的方式创建新的 OPTION 对象,也可以使用 new Option([text[, value[, defaultSelected[, selected]]]]) 或 document.createElement("option") 创建。创建 OPTION 对象的方法于本文测试结果无影响。

注2:Y 表示支持该方法,N 表示不支持。

注3:并没有实现在指定索引前插入 OPTION 的功能,只是实现了向 SELECT 元素尾部插入元素。

注4:并不是向 SELECT 元素的尾部插入 OPTION,而是插入到 SELECT 的首部。

解决方案

1. 在添加 OPTION 元素时

  • 如果需要向指定索引前插入 OPTION,可以使用 options.add(option, index);
  • 如果需要向 SELECT 尾部添加 OPTION,可以使用 options.add(option);
  • 如果需要向指定索引处添加(或更改) OPTION,可以使用 options[index] = option。

2. 在删除 OPTION 元素时

  • 如果想删除指定索引处的 OPTION 元素,可以使用 select.remove(index) 或 options[index] = null;
  • 如果想删除某个指定的 OPTION 元素,可以使用 select.remove(option);
  • 如果想删除 SELECT 中所有 OPTION,可以使用 select.length = 0 或 options.length = 0。

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6.9
Chrome 7.0.517.0 dev
Safari 5.0.1(7533.17.8)
Opera 10.62
测试页面: add_remove_option.html
本文更新时间: 2010-09-08

关键字

SELECT OPTION options add remove