被选中的选项被破坏还是......?

时间:2012-05-23 00:06:16

标签: javascript

注意:这个问题与Knockout.js无关,而是与selectedOptions元素的<select>属性相关。这是参考:

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#dom-select-selectedoptions

我认为这对Javascript开发人员来说是个不错的功能。支持非常有限,但无论如何都在增长。 Chrome,Opera和Safari应该已经支持它了。

问题在于我无法弄清楚它是如何工作的。行为应该非常简单,产生所选选项的实时集合,但结果并非如此。您可以想象每次用户选择一个选项时selectedOptions都会发生变化,对吗?错误。我准备了一个测试用例:

http://jsfiddle.net/f39cC/5/

在此示例中,Opera 11.64 始终返回所选的第一个值,无论您执行什么操作,而Chrome 21 dev和19 stable都有奇怪的行为。执行以下步骤:

  1. 选择“一个”。在输出和控制台中,您可以获得“One”,正如预期的那样。
  2. 使用Ctrl选择“Two”。在控制台中你得到“一,二”,在输出中它仍然是“一个”。
  3. 也选择“三个”。在控制台中它是“一,二,三”,在输出中它是“一,二”。
  4. 现在只选择“两个”。在控制台中,你得到“Two”,输出“Two ,,”(注意两个逗号)。
  5. 然而,如果您注释掉console.log行,则始终会获得正确的输出。如果交换两条指令,或者将值存储在单独的字符串中,您可以在控制台和输出中获得预期的行为,如下所示:

    http://jsfiddle.net/f39cC/2/

    那么,我错过了selectedOptions的一些内容吗?依赖这个属性是否为时尚早,可能有一个错误的实现? console.log是否在Chrome中造成了问题?关于HTMLCollection s,有什么我不知道的事情吗?

    我没有安装Safari,有人可以检查一下它的行为吗?

    更新日期18/2/2013 :我不知道什么时候发生了变化,但Chrome 24.0.1312.57和Opera 12.14现在似乎都运行良好。 Firefox 18.0.2和Internet Explorer 10仍然需要实现该属性。

    更新2013/3/13 :Firefox 24和IE 11预览版仍需支持该属性。这是Firefox和IE8-11的简单解决方法:

    Object.defineProperty(HTMLSelectElement.prototype, "selectedOptions", {
        get: (function() {
            try {
                document.querySelector(":checked");
                return function() {
                    return this.querySelectorAll(":checked");
                };
            } catch (e) {
                return function() {
                    if (!this.multiple) {
                        return this.selectedIndex >= 0
                                ? [this.options[this.selectedIndex]] : [];
                    }
                    for (var i = 0, a = []; i < this.options.length; i++)
                        if (this.options[i].selected) a.push(this.options[i]);
                    return a;
                };
            }
        })()
    });
    

    对于IE8,它只返回Array而不是NodeList

    更新28/5/2014 :从r25开始,Firefox似乎开始实施selectedOptions

1 个答案:

答案 0 :(得分:8)

似乎问题比一个简单的bug要深一点。 WebKit和Presto都无法正确支持selectedOptions的事实让我们暗示它依赖于该属性应该是HTMLCollection的事实。

现在,HTMLCollection具有它们的实时行为,因为当DOM发生某些事情(类的更改,节点的删除等)时,渲染引擎会使它们失效。但是选项selected属性不会触发集合的失效,从而使其完全不可靠。

我想这里的问题是以新的方式使实时集合失效,并且它可能不是很简单,因为它可能会影响解释和处理DOM的整个方式。

目前,Chrome 21.0.1180.4已删除该属性。