find('option[selected]') 和 find('option').filter('[selected]') 之间的区别是什么?(涉及IT技术)

9

场景:

我有两个 jQuery 表达式:

/* A */ $('select').find('option[selected]');
/* B */ $('select').find('option').filter('[selected]');

假设文档中只有一个 select,则:

  • A: 获取 select,然后查找所有具有名为 selected 的属性的 option 后代。
  • B: 获取 select,然后查找所有 option 后代,然后过滤出那些具有名为 selected 的属性的选项。

期望行为:

AB 应该给出相同的结果。

实际行为:

用户更改下拉列表中的选择后,

  • A 返回默认选中的 option
  • B 返回新选择的 option

问题:

所以它们为什么不同?我的 CSS 选择器理解有误吗?

演示:

演示在 这里 这里

源代码:

HTML

<select>
 <option value='p'>p</option> 
 <option value='q' selected>q</option>
 <option value='r'>r</option> 
 <option value='s'>s</option> 
</select>


<input type='button' value='click me!'/> <br/> 
 ResultA : <span id='ResultA'>
    here
</span> <br/> 
 ResultB : <span id='ResultB'>
    here
</span> <br/> 

Javascript

function SetResult(ResultObj, ElementObj) {
    ResultObj.text("length=" + ElementObj.length + " " + "val()=" + ElementObj.val());
}

$(function() {
    $('input[type=button]').click(function() {
        var SelectObj = $('select');
        SetResult($("#ResultA"), SelectObj.find('option[selected]'));
        SetResult($("#ResultB"), SelectObj.find('option').filter('[selected]'));
    });
});

测试结果:

+---------------------------+--------------+---------------------+---------+-----+
|          Browser          | Environment  |       jQuery        |    A    |  B  |
+---------------------------+--------------+---------------------+---------+-----+
| Chrome 22.0.1229.94m      | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Chrome 23.0.1271.64 m     | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Firefox 15.0.1            | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Firefox 16.0.2            | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
| IE 6                      | WinXP        | 1.8.2, 1.7.2, 1.6.4 | *new*   | new |
| IE 9                      | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Opera 12.02               | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Opera 12.10               | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Safari 5.1.7 (7534.57.2)  | Win7         | 1.8.2, 1.7.2, 1.6.4 | default | new |
+---------------------------+--------------+---------------------+---------+-----+
| Chrome 22.0.1229.94       | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Chrome 23.0.1271.64       | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Firefox 13.0              | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Firefox 14.0.1            | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Firefox 16.0.2            | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Opera 12.01               | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Opera 12.10               | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Safari 6.0.1 (7536.26.14) | MacOS 10.7.5 | 1.8.2, 1.7.2, 1.6.4 | default | new |
+---------------------------+--------------+---------------------+---------+-----+
| Chrome 21.0.1180.82       | iOS 4.3.5    | 1.8.2, 1.7.2, 1.6.4 | default | new |
| Opera 7.0.5               | iOS 4.3.5    | 1.8.2               | default | new |
| Safari                    | iOS 4.3.5    | 1.8.2, 1.7.2, 1.6.4 | default | new |
+---------------------------+--------------+---------------------+---------+-----+
  • default 表示返回默认选中的 option
  • new 表示返回新选中的 option

如您所见,除了 IE6 以外的所有浏览器都会给出不同的结果。


2
你对CSS选择器的理解似乎很不错。然而,jQuery并不总是基于源标记来选择元素。我发现,特别是对于那些值可能会改变的属性选择器,这一点尤其明显。虽然我不知道为什么jQuery会不一致地处理它们。 - BoltClock
2
顺便提一下:对于 #ResultA,使用 option:selected 而不是 option[selected] 将产生与 #ResultB 相同的输出。 - sp00m
@sp00m:我开始非常非常地讨厌Sizzle了。 - BoltClock
1
在 jQuery 1.7 之前的版本中,这些选择器未能返回相同的值,详见此错误报告 - Mottie
5个回答

3
Sizzle引擎检查元素的selected 属性(包含当前值)而不是包含原始(默认)值的属性。请参见 https://github.com/jquery/sizzle/blob/master/sizzle.js#L788。无论如何,您应该检查属性而不是属性,因此应该使用:selected伪选择器,而不是[selected]。我还没有弄清楚为什么第二个选择器显然会调用Sizzle,但第一个选择器似乎没有。

1
dmethvin在这个问题中解释了区别::selected的问题是通过Sizzle的JavaScript路径查找属性,而[selected]则通过querySelectorAll路径查找属性。(除非字符串中有其他非qSA选择器,例如[selected]:first。) - Mottie
@Mottie确实,除了我使用调试器并发现.filter('[selected]')没有经过:selected Sizzle代码。很奇怪... - Alnitak

1

表达式应该返回什么?

[selected]匹配所有具有selected属性的元素,其值可以是任何值(参考:W3C, jQuery)。


为什么结果不一致?

我已经向jQuery 这里 提交了一个错误报告。它被标记为另一个错误报告的重复,该问题现在已经修复


有什么解决方案吗?

要获取当前选择

使用{{link1::selected}}选择器(演示请点击这里):

$('select').find('option').filter(':selected'); /* Supposedly faster */
or
$('select').find('option:selected');            /* Supposedly slower */

请注意,根据doc,第二个表达式应该是较慢的。

由于:selected是jQuery扩展而不是CSS规范的一部分,使用:selected的查询无法利用本机DOM querySelectorAll()方法提供的性能提升。

要获取默认选择

对于jQuery 1.9+,使用问题中的任何表达式即可。

/* A */ $('select').find('option[selected]');
/* B */ $('select').find('option').filter('[selected]');

对于jQuery 1.6+,请使用defaultSelected属性(演示示例 here,参考文献:w3schoolsMozillaMSDNMSDN):

$('select').find('option').filter(function() {
    return $(this).prop('defaultSelected');
});

1

当你写 option[selected] 时,它会搜索 selected 属性/属性值,而不是这样,你应该使用 option:selected 如果你有 readonly 属性并且你编写 option[readonly] 它将返回 s

$('[attribute]') 将选择具有指定属性的元素,具有任何值。
更多信息:Has Attribute Selector [name]

Fiddle

<select>
 <option value='p'>p</option> 
 <option value='q' selected>q</option>
 <option value='r'>r</option> 
 <option value='s' readonly>s</option> 
</select>  

0
这取决于浏览器如何构建DOM。使用option[selected] jQuery搜索具有选定属性的选项元素,在某些情况下,它可能不适用。
你应该使用:
SelectObj.children(':selected')

.filter('[selected]') 过滤选项,包含了被选中的属性...问题是为什么。 - sp00m

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接