当有多个元素具有相同的 ID 值时,jQuery 如何工作?

我从谷歌的 AdWords 网站获取数据,该网站有多个元素,具有相同的 id

能否请您解释一下为什么以下3个查询不能得到相同的答案(2) ?

现场演示

HTML:

<div>
<span id="a">1</span>
<span id="a">2</span>
<span>3</span>
</div>

约翰逊:

$(function() {
var w = $("div");
console.log($("#a").length);            // 1 - Why?
console.log($("body #a").length);       // 2
console.log($("#a", w).length);         // 2
});
146524 次浏览

根据 W3C 规范,拥有两个具有相同 ID 的元素是无效的 html。

当您的 CSS 选择器只有一个 ID 选择器(并且不在特定的上下文中使用)时,jQuery 使用本机 document.getElementById方法,该方法只返回具有该 ID 的第一个元素。

然而,在另外两个实例中,jQuery 依赖于 Sizzle 选择器引擎(或者 querySelectorAll,如果可用的话) ,它显然选择了这两个元素。每个浏览器的结果可能有所不同。

但是,在同一页面上不应该有两个具有相同 ID 的元素。如果您的 CSS 需要它,可以使用类代替。


如果您必须使用重复的 ID 进行选择,请使用属性选择器:

$('[id="a"]');

看看小提琴: http://jsfiddle.net/P2j3f/2/

注意: 如果可能的话,您应该使用类型选择器限定该选择器,如下所示:

$('span[id="a"]');

这是因为类型选择器比属性选择器效率高得多。如果用类型选择器限定属性选择器,jQuery 将首先使用类型选择器查找该类型的元素,然后只对这些元素运行属性选择器。这样更有效率。

应该只有一个元素具有给定的 id。如果你被这种情况困住了,看看我的答案的后半部分的选择。

当多个元素具有相同的 id (非法 HTML)时,浏览器的行为不是由规范定义的。您可以测试所有的浏览器并了解它们的行为,但是使用这种配置或依赖于任何特定的行为都是不明智的。

如果希望多个对象具有相同的标识符,则使用类。

<div>
<span class="a">1</span>
<span class="a">2</span>
<span>3</span>
</div>


$(function() {
var w = $("div");
console.log($(".a").length);            // 2
console.log($("body .a").length);       // 2
console.log($(".a", w).length);         // 2
});

如果由于无法修复文档而希望可靠地查看 ID 相同的元素,那么必须自己进行迭代,因为不能依赖任何内置的 DOM 函数。

你可以这样做:

function findMultiID(id) {
var results = [];
var children = $("div").get(0).children;
for (var i = 0; i < children.length; i++) {
if (children[i].id == id) {
results.push(children[i]);
}
}
return(results);
}

或者,使用 jQuery:

$("div *").filter(function() {return(this.id == "a");});

JQuery 工作示例: http://jsfiddle.net/jfriend00/XY2tX/

至于为什么会得到不同的结果,这与实际执行选择器操作的代码片段的内部实现有关。在 jQuery 中,您可以研究代码来找出任何给定的版本在做什么,但是由于这是非法的 HTML,因此不能保证它在一段时间内保持不变。从我在 jQuery 中看到的情况来看,它首先检查选择器是否是像 #a那样的简单 id,如果是,就使用 document.getElementById("a")。如果选择器比这个更复杂,而且 querySelectorAll()存在,jQuery 通常会将选择器传递给内置的浏览器函数,该函数将具有特定于该浏览器的实现。如果 querySelectorAll()不存在,那么它将使用 Sizzle 选择器引擎手动查找具有自己实现的选择器。因此,您可以在同一个浏览器家族中至少有三种不同的实现,这取决于确切的选择器和浏览器的新程度。然后,各个浏览器都将有自己的 querySelectorAll()实现。如果您想可靠地处理这种情况,您可能必须使用您自己的迭代代码,正如我在上面所说明的。

JQuery 的 id选择器只返回一个结果。第二和第三个语句中的 descendantmultiple选择器被设计用于选择多个元素。它类似于:

声明1

var length = document.getElementById('a').length;

只有一个结果。

声明2

var length = 0;
for (i=0; i<document.body.childNodes.length; i++) {
if (document.body.childNodes.item(i).id == 'a') {
length++;
}
}

产生两个结果。

声明3

var length = document.getElementById('a').length + document.getElementsByTagName('div').length;

也会产生两个结果。

来自 选择器 jQuery 页面:

每个 id 值在文档中只能使用一次。如果多个元素被分配了相同的 ID,那么使用该 ID 的查询将只选择 DOM 中第一个匹配的元素。但是,不应该依赖此行为; 使用相同 ID 的多个元素的文档是无效的。

淘气的谷歌。但我听说他们甚至不关闭 <html><body>的标签。但问题是,为什么 Misha 的第2和第3个查询返回2而不是1。

如果您有多个元素具有相同的 id 或相同的名称,只要分配相同的类到这些多个元素,并通过索引访问它们,并执行所需的操作。

  <div>
<span id="a" class="demo">1</span>
<span id="a" class="demo">2</span>
<span>3</span>
</div>

JQ:

$($(".demo")[0]).val("First span");
$($(".demo")[1]).val("Second span");

你可以简单地写 $(‘ span # a’) . length 来得到长度。

下面是您的代码的解决方案:

console.log($('span#a').length);

试试 JSfiddle: Https://jsfiddle.net/vickyfor2007/wcc0ab5g/2/

当一个愚蠢的页面有多个元素具有相同的 ID 时,我们如何获得所需的元素呢?如果我们使用’# douplicatedId’,我们只获得第一个元素。为了选择其他元素,你可以这样做:

$("[id=duplicatedId]")

您将得到一个集合,其中所有元素都带有 id = double icatedId。

访问个别项目

<div id='a' data-options='{"url","www.google.com"}'>Google</div>
<div id='a' data-options='{"url","www.facebook.com"}'>Facebook</div>
<div id='a' data-options='{"url","www.twitter.com"}'>Twitter</div>




$( "div[id='a']" ).on('click', function() {
$(location).attr('href', $(this).data('options').url);
});