【发布时间】:2012-05-23 00:06:15
【问题描述】:
注意:这个问题与 Knockout.js 无关,而是与 <select> 元素的 selectedOptions 属性有关。这是参考:
我认为这对 Javascript 开发人员来说是一个不错的功能。支持非常有限,但无论如何它都在增长。 Chrome、Opera 和 Safari 应该已经支持它了。
问题是我无法弄清楚它是如何工作的。该行为应该非常简单,产生所选选项的实时集合,但事实并非如此。您可以想象,每次用户选择一个选项时,selectedOptions 都会发生变化,对吧?错误的。我准备了一个测试用例:
在这个例子中,Opera 11.64 always 返回第一个选择的值,不管你做什么,而 Chrome 21 dev 和 19 stable 有一个奇怪的行为。执行以下步骤:
- 选择“一个”。正如预期的那样,在输出和控制台中,您都会得到“One”。
- 也选择“两个”,使用 Ctrl。在控制台中你得到“一,二”,在输出中它仍然是“一”。
- 也选择“三”。在控制台中是“一、二、三”,在输出中是“一、二”。
- 现在只选择“两个”。在控制台中你会得到“Two”,在输出中你会得到“Two,”(注意两个逗号)。
但是,如果您注释掉 console.log 行,您总是会得到正确的输出。如果交换两条指令,或者将值存储在单独的字符串中,则可以在控制台和输出中获得预期的行为,如下所示:
那么,我是否错过了关于 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 中的<select>元素和Opera,它可以有一个至少可以类似于规范的实现。它在 both 用户代理中被破坏的事实让我完全措手不及,我认为我错过了一些东西,因为它看起来是一个非常简单的功能。我前几天在 Chromium 项目中打开了一个 issue,感谢您的确认。 -
我看到你甚至打开了chrome的票,所以我什至没有“打扰”回答......
:)我相信你的回答会比我的好,你应该这样做. -
@BrettZamir 它确实有效,但
Array.from很难看:一个简单的[].slice.call(this.options)肯定会更快。但是一切都可以改变,因为filter比for循环慢。通常我也会介意创建用户定义类的对象,但毕竟这些集合通常非常小。
标签: javascript