Cách tốt nhất để có được các nút con


233

Tôi đã tự hỏi, JavaScript cung cấp nhiều phương thức khác nhau để có được phần tử con đầu tiên từ bất kỳ phần tử nào, nhưng phương thức nào là tốt nhất? Theo ý tôi, tốt nhất là: hầu hết các trình duyệt tương thích, nhanh nhất, toàn diện nhất và có thể dự đoán được khi nói về hành vi. Danh sách các phương thức / thuộc tính tôi sử dụng làm bí danh:

var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]

Điều này làm việc cho cả hai trường hợp:

var child = elem.childNodes[0]; // or childNodes[1], see below

Đó là trong trường hợp của các hình thức, hoặc <div>lặp đi lặp lại. Nếu tôi có thể gặp các yếu tố văn bản:

var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;

Theo như tôi có thể làm việc, firstChildsử dụng NodeList từ childNodesfirstElementChildsử dụng children. Tôi dựa trên giả định này trên tài liệu tham khảo MDN:

childNodelà một tham chiếu đến phần tử con đầu tiên của nút phần tử hoặc nullnếu không có phần tử nào .

Tôi đoán rằng, về mặt tốc độ, sự khác biệt, nếu có, sẽ không có gì, vì thực sự firstElementChildlà một tài liệu tham khảo children[0]childrendù sao đối tượng cũng đã có trong bộ nhớ.

Những gì không ném tôi, là childNodesđối tượng. Tôi đã sử dụng nó để xem biểu mẫu, trong phần tử bảng. Mặc dù childrenliệt kê tất cả các thành phần của biểu mẫu, childNodesdường như cũng bao gồm khoảng trắng từ mã HTML:

console.log(elem.childNodes[0]);
console.log(elem.firstChild);

Cả hai bản ghi <TextNode textContent="\n ">

console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);

Tất cả các bản ghi <input type="text"... >. Làm thế nào mà? Tôi hiểu rằng một đối tượng sẽ cho phép tôi làm việc với mã HTML thô của HTML, trong khi các đối tượng khác dính vào DOM, nhưng childNodesphần tử này dường như hoạt động ở cả hai cấp độ.

Để quay trở lại câu hỏi ban đầu của tôi, tôi đoán là: nếu tôi muốn đối tượng toàn diện nhất, childNodeslà cách để đi, nhưng vì tính toàn diện của nó, nó có thể không được dự đoán nhiều nhất về việc nó trả lại yếu tố tôi muốn / mong đợi tại bất kỳ thời điểm nào. Hỗ trợ nhiều trình duyệt cũng có thể chứng minh là một thách thức trong trường hợp đó, mặc dù tôi có thể sai.

Bất cứ ai có thể làm rõ sự phân biệt giữa các đối tượng trong tầm tay? Nếu có sự khác biệt về tốc độ, tuy nhiên không đáng kể, tôi cũng muốn biết. Nếu tôi thấy điều này là sai, hãy thoải mái giáo dục tôi.


PS: Làm ơn, làm ơn, tôi thích JavaScript, nên vâng, tôi muốn giải quyết vấn đề này. Các câu trả lời như Giao dịch jQuery với điều này cho bạn, không phải là những gì tôi đang tìm kiếm, do đó không nhãn.


49
>> làm ơn, làm ơn, tôi thích JavaScript, nên vâng, tôi muốn giải quyết vấn đề này. các câu trả lời như 'jQuery giải quyết vấn đề này cho bạn' không phải là điều tôi đang tìm kiếm <<
upvote

Câu trả lời:


211

Âm thanh như bạn đang lật đổ nó. Bạn đã quan sát sự khác biệt giữa childNodeschildren, trong đó childNodescó chứa tất cả các nút, bao gồm các nút văn bản bao gồm toàn bộ khoảng trắng, trong khi đó childrenlà một tập hợp chỉ các nút con là các phần tử. Đó thực sự là tất cả để có nó.

Không có gì khó đoán về cả bộ sưu tập, mặc dù có một số vấn đề cần lưu ý:

  • IE <= 8 không bao gồm các nút văn bản chỉ có khoảng trắng trong childNodeskhi các trình duyệt khác làm
  • IE <= 8 bao gồm các nút nhận xét trong childrenkhi các trình duyệt khác chỉ có các yếu tố

children, firstElementChildVà bạn bè chỉ là tiện, trình bày một cái nhìn lọc của DOM hạn chế để chỉ yếu tố.


Hình như nhiều, mặc dù có một điều vẫn làm tôi bực mình: mã văn bản khoảng trắng mà childNodes chọn trên thực tế chỉ là một dòng mới và một vài tab trong mã. Đây có phải là do tài liệu XHTML không? điều này có thể được giải quyết bằng cách đặt khoảng trắng vào mã cấu trúc trong các thẻ không?
Elias Van Ootegem

@EliasVanOotegem: Điều đó không liên quan đến doctype. Các nút văn bản khoảng trắng luôn được bao gồm trong DOM (ngoại trừ trong IE <9) cho cả HTML và XHTML, bất cứ nơi nào chúng xuất hiện trong nguồn. Nói chung đó là một điều tốt, mặc dù nó có thể đuổi bạn ra nếu bạn không chuẩn bị cho nó.
Tim Down

Tôi có nghĩa là nếu nó sẽ giúp viết đánh dấu của tôi như thế này <td\n\t>content</td>. Như bạn có thể làm với XML, để tránh khoảng trắng thừa được coi là một phần của dữ liệu (hoặc DOM, trong trường hợp này). Tại sao khoảng trắng bên trong thẻ sẽ được đưa vào DOM?
Elias Van Ootegem

@EliasVanOotegem: Ồ, tôi hiểu rồi. Khoảng trắng sau khi tên thẻ bên trong thẻ bị bỏ qua, vì vậy bạn có thể thực hiện loại điều đó. Tôi đã thấy rằng kỹ thuật được sử dụng trong các bố cục chính xác để ngăn các trình duyệt thêm các khoảng trống nhỏ cho khoảng trắng giữa một số loại yếu tố.
Tim Down

2
@Christophe: Ah, điểm công bằng, cảm ơn. Tôi sẽ thêm một ghi chú cho câu trả lời của tôi. Cho rằng childrencó nguồn gốc từ IE 4 hơn một thập kỷ trước khi trở thành một tiêu chuẩn hoặc được các trình duyệt khác chấp nhận, bạn có thể lập luận rằng IE <= 8 là chính xác và các trình duyệt khác là sai.
Tim Down

23

FirstEuityChild có thể không khả dụng trong IE <9 (chỉ FirstChild)

trên IE <9 FirstChild là FirstEuityChild vì MS DOM (IE <9) không lưu trữ các nút văn bản trống. Nhưng nếu bạn làm như vậy trên các trình duyệt khác, chúng sẽ trả về các nút văn bản trống ...

giải pháp của tôi

child=(elem.firstElementChild||elem.firstChild)

điều này sẽ sinh con đầu lòng ngay cả trên IE <9


Nếu elem.firstChildkhông phải là nút phần tử, kết quả sẽ khác trong các IE cũ, vì elem.firstElementChildluôn là nút phần tử.
duri

Tôi xin lỗi, nhưng tôi biết làm thế nào để có được đứa con đầu tiên trong tất cả các trình duyệt chính. Những gì tôi muốn biết là làm thế nào các đối tượng khác nhau được cấu trúc, để có được sự hiểu biết tốt hơn về sự tương đồng và khác biệt giữa chúng. Tôi sẽ chỉnh sửa câu hỏi của mình sau để làm cho rõ ràng hơn, xin lỗi vì sự pha trộn
Elias Van Ootegem

1
firstElementChildcũng không hẳn là an toàn trong các trình duyệt không phải IE: Firefox chỉ bắt đầu hỗ trợ nó trong phiên bản 3.5.
Tim Down

cái này hoạt động với chrome, IE9 và IE8 bởi vì nếu chúng có FirstEuityChild thì kiểm tra khác không được thực thi, nếu không (IE cũ) chúng ta có FirstChild và đó là nút phần tử cho trình duyệt không có FirstEuityChild (IE <9 ) ... tôi vẫn thắc mắc về FF
neu-rah

1
Tim là chính xác, khi tôi đang tìm kiếm những thứ trên các vật thể này xuất hiện, trang web tốt để kiểm tra một lần
Elias Van Ootegem

20

Cách làm của trình duyệt chéo là sử dụng childNodesđể có được NodeList, sau đó tạo một mảng gồm tất cả các nút với nodeType Element_NODE .

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    var childNodes = element.childNodes,
        children = [],
        i = childNodes.length;

    while (i--) {
        if (childNodes[i].nodeType == 1) {
            children.unshift(childNodes[i]);
        }
    }

    return children;
}

http://jsfiddle.net/s4kxnahu/

Điều này đặc biệt dễ dàng nếu bạn đang sử dụng một thư viện tiện ích như lodash :

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    return _.where(element.childNodes, {nodeType: 1});
}

Tương lai:

Bạn có thể sử dụng querySelectorAllkết hợp với :scopelớp giả (khớp với phần tử là điểm tham chiếu của bộ chọn):

parentElement.querySelectorAll(':scope > *');

Tại thời điểm viết bài này :scopeđược hỗ trợ trong Chrome, Firefox và Safari.


: scope đã bị xóa khỏi spec . Chúng ta có nên loại bỏ phần Tương lai ?
Thomas Marti

4

Chỉ cần thêm vào các câu trả lời khác, vẫn có những khác biệt đáng chú ý ở đây, đặc biệt là khi làm việc với <svg>các yếu tố.

Tôi đã sử dụng cả hai .childNodes.childrenthích làm việc với người HTMLCollectiongiao hàng hơn .children.

Tuy nhiên, hôm nay, tôi gặp vấn đề với IE / Edge không thành công khi sử dụng .childrentrên <svg>. Mặc dù .childrenđược hỗ trợ trong IE trên các phần tử HTML cơ bản, nhưng nó không được hỗ trợ trên các đoạn tài liệu / tài liệu hoặc các phần tử SVG .

Đối với tôi, tôi chỉ có thể lấy các yếu tố cần thiết thông qua .childNodes[n]vì tôi không phải lo lắng về các nút văn bản bên ngoài. Bạn có thể làm tương tự, nhưng như đã đề cập ở trên, đừng quên rằng bạn có thể gặp phải các yếu tố bất ngờ.

Hy vọng điều này hữu ích cho ai đó gãi đầu cố gắng tìm ra lý do tại sao .childrenhoạt động ở nơi khác trong js của họ trên IE hiện đại và thất bại trên các yếu tố tài liệu hoặc SVG.


3

Này các bạn đừng để không gian trắng đánh lừa bạn. chỉ cần kiểm tra điều này trong một trình duyệt giao diện điều khiển. sử dụng javascript gốc. Dưới đây là ví dụ với hai bộ 'ul' có cùng lớp. Bạn không cần phải có tất cả danh sách 'ul' trong một dòng để tránh khoảng trắng, chỉ cần sử dụng số mảng của bạn để nhảy qua khoảng trắng.

Làm thế nào để có được không gian xung quanh màu trắng với querySelector()sau đó childNodes[]js liên kết fiddle: https://jsfiddle.net/aparadise/56njekdo/

var y = document.querySelector('.list');
var myNode = y.childNodes[11].style.backgroundColor='red';

<ul class="list">
    <li>8</li>
    <li>9</li>
    <li>100</li>
</ul>

<ul class="list">
    <li>ABC</li>
    <li>DEF</li>
    <li>XYZ</li>
</ul>

Không phải tôi bỏ phiếu, nhưng tôi nghĩ ai đó đã bỏ phiếu vì: a) Câu hỏi này đã 4 tuổi, document.querySelectorlúc đó không được hỗ trợ tốt. b) Câu hỏi về cơ bản là hỏi sự khác biệt giữa childrenchildNodes bên trong là gì, đáng tin cậy hơn, khi nào nên chọn cái khác. và c) Bởi vì, như được giải thích trong câu hỏi: childNodes không bao gồm các nút khoảng trắng, childrenkhông ...
Elias Van Ootegem
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.