2011-12-14 33 views
53

Tôi tìm nạp dữ liệu từ trang web AdWords của Google có nhiều thành phần với cùng một số id.Cách jQuery hoạt động khi có nhiều phần tử có cùng "id"?

Bạn có thể giải thích tại sao 3 truy vấn sau đây không có cùng câu trả lời (2) không?

Live Demo

HTML:

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

JS:

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

Trả lời

66

Có 2 yếu tố với cùng một ID không phải là html hợp lệ theo đặc điểm kỹ thuật của W3C.

Khi bộ chọn CSS của bạn chỉ có bộ chọn ID (và không được sử dụng trong ngữ cảnh cụ thể), jQuery sử dụng phương thức gốc document.getElementById, chỉ trả về phần tử đầu tiên có ID đó.

Tuy nhiên, trong hai trường hợp còn lại, jQuery dựa vào công cụ chọn Sizzle (hoặc querySelectorAll, nếu có), mà rõ ràng chọn cả hai phần tử. Kết quả có thể khác nhau tùy theo từng trình duyệt.

Tuy nhiên, bạn không bao giờ nên có hai phần tử trên cùng một trang với cùng một ID. Nếu bạn cần nó cho CSS của bạn, hãy sử dụng một lớp thay thế.


Nếu bắt buộc phải chọn bởi ID trùng lặp, sử dụng một bộ chọn thuộc tính:

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

Hãy xem fiddle: http://jsfiddle.net/P2j3f/2/

Lưu ý: nếu có thể, bạn nên đủ điều kiện bộ chọn có bộ chọn thẻ, như sau:

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

thể bạn vui lòng giải thích ** Lưu ý **? Khi thêm công cụ chọn thẻ là hữu ích? –

+4

@Misha Moroshko - Bất cứ khi nào có thể, bạn nên bao gồm bộ chọn thẻ. Lý do cho điều này là do bộ chọn thẻ là * nhiều * hiệu quả hơn bộ chọn thuộc tính. Nếu bạn đủ điều kiện bộ chọn thuộc tính của bạn với bộ chọn thẻ, trước tiên jQuery sẽ sử dụng công cụ chọn thẻ để tìm các phần tử có thẻ đó và sau đó chỉ chạy bộ chọn thuộc tính trên các phần tử đó. Điều này đơn giản hơn nhiều. –

+2

Tôi thấy ở đây 'div # some_id' chậm hơn' # some_id': http://stackoverflow.com/q/7262116/247243 –

3

Chỉ nên có một phần tử có id đã cho. Nếu bạn bị mắc kẹt với tình huống đó, hãy xem phần thứ hai của câu trả lời của tôi cho các tùy chọn.

Cách trình duyệt hoạt động khi bạn có nhiều phần tử có cùng id (HTML bất hợp pháp) không được xác định theo đặc điểm kỹ thuật. Bạn có thể kiểm tra tất cả các trình duyệt và tìm hiểu cách chúng hoạt động, nhưng không khôn ngoan khi sử dụng cấu hình này hoặc dựa vào bất kỳ hành vi cụ thể nào.

Sử dụng các lớp nếu bạn muốn nhiều đối tượng có cùng số nhận dạng.

<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 
}); 

Nếu bạn muốn chắc chắn nhìn vào các yếu tố với ID đó đều giống nhau vì bạn không thể sửa chữa các tài liệu, sau đó bạn sẽ phải làm lặp riêng của bạn khi bạn không thể dựa vào bất cứ việc xây dựng trong DOM chức năng.

Bạn có thể làm như vậy như thế này:

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); 
} 

Hoặc, sử dụng jQuery:

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

jQuery dụ làm việc: http://jsfiddle.net/jfriend00/XY2tX/.

Tại sao bạn nhận được các kết quả khác nhau, điều đó sẽ liên quan đến việc triển khai nội bộ bất kỳ đoạn mã nào đang thực hiện thao tác chọn thực tế. Trong jQuery, bạn có thể nghiên cứu mã để tìm hiểu xem bất kỳ phiên bản nào đã làm, nhưng vì đây là HTML bất hợp pháp, không có gì đảm bảo rằng nó sẽ giữ nguyên theo thời gian. Từ những gì tôi đã nhìn thấy trong jQuery, trước tiên nó kiểm tra xem bộ chọn là một id đơn giản như #a và nếu có, chỉ cần sử dụng document.getElementById("a"). Nếu bộ chọn phức tạp hơn và querySelectorAll() tồn tại, jQuery thường sẽ chuyển bộ chọn ra thành chức năng trình duyệt được tích hợp sẵn sẽ có một cài đặt cụ thể cho trình duyệt đó. Nếu querySelectorAll() không tồn tại, thì nó sẽ sử dụng công cụ chọn Sizzle để tìm thủ công bộ chọn sẽ có cài đặt riêng. Vì vậy, bạn có thể có ít nhất ba triển khai khác nhau trong cùng một gia đình trình duyệt tùy thuộc vào bộ chọn chính xác và trình duyệt mới như thế nào. Sau đó, tất cả các trình duyệt riêng lẻ sẽ có các triển khai querySelectorAll() riêng của chúng. Nếu bạn muốn xử lý một cách đáng tin cậy với tình huống này, có thể bạn sẽ phải sử dụng mã lặp của riêng mình như tôi đã minh họa ở trên.

+0

Anh ấy không thể. Anh ấy nhận được nó từ Google, đó là vấn đề –

+0

@RalphLavelle - Tôi đã thêm một phương thức xử lý các ID kép nếu bạn bị kẹt với nó. – jfriend00

2

Bộ chọn id của jQuery chỉ trả lại một kết quả. Các bộ chọn descendantmultiple trong câu lệnh thứ hai và thứ ba được thiết kế để chọn nhiều phần tử. Nó tương tự như:

Tuyên Bố 1

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

... Sản lượng một kết quả.

Tuyên Bố 2

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

... Sản lượng hai kết quả.

Tuyên Bố 3

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

... Cũng mang lại hai kết quả.

2

Từ id Selector jQuery page:

Mỗi giá trị id phải được sử dụng một lần duy nhất trong một tài liệu. Nếu có nhiều hơn một phần tử đã được gán cùng một ID, các truy vấn sử dụng ID đó sẽ chỉ chọn phần tử được so khớp đầu tiên trong DOM. Tuy nhiên, hành vi này không nên dựa vào; tài liệu có nhiều hơn một phần tử sử dụng cùng một ID không hợp lệ.

Naughty Google. Nhưng họ thậm chí không đóng các thẻ <html><body> của tôi. Câu hỏi đặt ra là, tại sao các truy vấn thứ 2 và thứ 3 của Misha trả về 2 và không phải là 1.

0

Nếu bạn có nhiều thành phần có cùng id hoặc cùng tên, chỉ cần gán cùng một lớp cho nhiều thành phần đó và truy cập chúng theo chỉ mục & thực hiện thao tác bắt buộc của bạn.

<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"); 
0

bạn chỉ có thể viết $ ('# khoảng một') chiều dài để có được độ dài.

Đây là giải pháp cho mã của bạn:

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

thử JSfiddle: https://jsfiddle.net/vickyfor2007/wcc0ab5g/2/

Các vấn đề liên quan