【问题标题】:Is selectedOptions broken or...?selectedOptions 是否损坏或...?
【发布时间】:2012-05-23 00:06:15
【问题描述】:

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

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 always 返回第一个选择的值,不管你做什么,而 Chrome 21 dev 和 19 stable 有一个奇怪的行为。执行以下步骤:

  1. 选择“一个”。正如预期的那样,在输出和控制台中,您都会得到“One”。
  2. 也选择“两个”,使用 Ctrl。在控制台中你得到“一,二”,在输出中它仍然是“一”。
  3. 也选择“三”。在控制台中是“一、二、三”,在输出中是“一、二”。
  4. 现在只选择“两个”。在控制台中你会得到“Two”,在输出中你会得到“Two,”(注意两个逗号)。

但是,如果您注释掉 console.log 行,您总是会得到正确的输出。如果交换两条指令,或者将值存储在单独的字符串中,则可以在控制台和输出中获得预期的行为,如下所示:

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

那么,我是否错过了关于 selectedOptions 的某些内容?依赖这个可能有错误实现的属性是否为时过早? console.log 是在 Chrome 中创建问题吗? HTMLCollections 有什么我不知道的地方吗?

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

2013 年 2 月 18 日更新:我不知道什么时候发生了变化,但 Chrome 24.0.1312.57 和 Opera 12.14 现在似乎都可以正常工作了。 Firefox 18.0.2 和 Internet Explorer 10 仍需实现该属性。

2013 年 9 月 17 日更新: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 更新:看起来 Firefox 从 r25 开始实施 selectedOptions

【问题讨论】:

  • 根据我的研究,是的,它坏了,wasn't even implemented in firefox。我可以把它写成答案,但你现在可能已经知道了……
  • 是的,我什至在发布这个问题之前就已经阅读了那个错误页面,但我希望如此,因为 selectedOption 定义在 Chrome 中的 &lt;select&gt; 元素和Opera,它可以有一个至少可以类似于规范的实现。它在 both 用户代理中被破坏的事实让我完全措手不及,我认为我错过了一些东西,因为它看起来是一个非常简单的功能。我前几天在 Chromium 项目中打开了一个 issue,感谢您的确认。
  • 我看到你甚至打开了chrome的票,所以我什至没有“打扰”回答......:)我相信你的回答会比我的好,你应该这样做.
  • @BrettZamir 它确实有效,但 Array.from 很难看:一个简单的 [].slice.call(this.options) 肯定会更快。但是一切都可以改变,因为filterfor 循环慢。通常我也会介意创建用户定义类的对象,但毕竟这些集合通常非常小。

标签: javascript


【解决方案1】:

似乎这个问题比一个简单的错误要深一些。 WebKit 和 Presto 都未能正确支持 selectedOptions 的事实给我们暗示,这取决于属性应该是 HTMLCollection 的事实。

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

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

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

【讨论】:

猜你喜欢
  • 2012-04-13
  • 1970-01-01
  • 2011-10-02
  • 2021-11-28
  • 2011-01-28
  • 2013-12-02
  • 2011-02-15
  • 1970-01-01
  • 2011-03-01
相关资源
最近更新 更多