2012-04-17 30 views
19

Giả sử bạn có danh sách có danh sách con lồng nhau.Bộ chọn con bằng cách sử dụng `querySelectorAll` trên bộ sưu tập DOM

<ul> 
    <li></li> 
    <li> 
     <ul> 
      <li></li> 
      <li></li> 
     </ul> 
    </li> 
    <li></li> 
</ul> 

Và sử dụng document.querySelectorAll() để thực hiện một lựa chọn:

var ul = document.querySelectorAll("ul"); 

Làm thế nào tôi có thể sử dụng bộ sưu tập ul để có được những yếu tố con trực tiếp?

ul.querySelectorAll("> li"); 
// Gives 'Error: An invalid or illegal string was specified' 

Hãy đoán ul được lưu trữ bằng cách nào đó (nếu không tôi đã có thể làm ul > li trực tiếp).

Trong jQuery làm việc này:

$("ul").find("> li"); 

Nhưng nó không có nguồn gốc trong querySelectorAll. Bất kỳ giải pháp?

+2

Đó chọn không thực sự có ý nghĩa. Với jQuery bạn sẽ sử dụng '.children (" li ")' thay vì '.find ("> li ")'. Tôi ngạc nhiên khi làm việc ở tất cả, thực sự. –

+0

@ MДΓΓБДLL '.find ('> li ul span')' rất hữu ích, nhưng không quá nhiều theo cách riêng của nó như trong ví dụ của OP. – alex

+0

@ MДΓΓБДLL ví dụ là một chút contrived, nhưng nó chắc chắn có một trường hợp sử dụng thực tế :) – Husky

Trả lời

12

Bởi vì ul được trả lại là một NodeList, nó không ngầm lặp lại nội dung của nó như một bộ sưu tập jQuery. Bạn cần sử dụng ul[0].querySelectorAll() hoặc tốt hơn vẫn chọn ul với querySelector().

Bên cạnh đó, querySelectorAll() sẽ không chụp > và hoạt động từ ngữ cảnh hiện tại của nó. Tuy nhiên, bạn có thể lấy nó để làm việc bằng lazd's answer (mặc dù kiểm tra khả năng tương thích trình duyệt), hoặc bất kỳ các biện pháp khắc phục (mà nên không có vấn đề trình duyệt) ...

[].filter.call(ul.querySelectorAll("li"), function(element){ 
    return element.parentNode == ul; 
}); 

jsFiddle.

Điều này sẽ chọn tất cả các phần tử li là hậu duệ của ul của bạn và sau đó xóa những phần tử không phải là hậu duệ trực tiếp.

Ngoài ra, bạn có thể nhận được tất cả childNodes và sau đó lọc chúng ...

[].filter.call(ul.childNodes, function(node) { 
    return node.nodeType == 1 && node.tagName.toLowerCase() == 'li'; 
}); 

jsFiddle.

+0

Yup, mà có vẻ như một giải pháp khả thi.Quá xấu phải mất ba dòng mã những gì có thể được thực hiện trong một ký tự đơn :) Lưu ý rằng 'filter()' sẽ không hoạt động vì 'ul' là một NodeList, vì vậy bạn cần phải làm' Array.prototype.slice .call' trước. – Husky

+0

@ Husky Nó sẽ hoạt động theo cách mà tôi đã viết nó. – alex

+0

@Husky Bạn luôn có thể thêm nó vào 'Element.prototype' làm hàm :) –

0

Bạn cần lặp lại trên NodeList được trả về document.querySelectorAll() và sau đó gọi element.querySelectorAll() cho từng phần tử trong danh sách đó.

36

Cách đúng để viết bộ chọn được "bắt nguồn" vào phần tử hiện tại là sử dụng :scope.

ul.querySelectorAll(":scope > li"); 

Xem câu trả lời của tôi ở đây cho một lời giải thích và một mạnh mẽ, giải pháp qua trình duyệt: https://stackoverflow.com/a/21126966/1170723

+2

Tốt để thấy điều này tồn tại! :) – alex

+5

Hãy ghi nhớ [khả năng tương thích của trình duyệt] (https://developer.mozilla.org/en-US/docs/Web/CSS/%3ascope#Browser_compatibility): Chrome: có, FF: 32, IE: không, opera: không, Safari: 7 –

+0

ngoài những gì @Web_Designer cho biết, cho đến ngày nay nó vẫn * vẫn * không được hỗ trợ trong Microsoft Edge. Cố gắng sử dụng 'scope' trong querySelectorAll đưa ra một lỗi cú pháp. Rất nhiều cho "bạn không cần jQuery" trại. – TKoL

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