Cách kiểm tra Javascript nếu một yếu tố được chứa trong một yếu tố khác


202

Làm cách nào để kiểm tra xem một phần tử DOM có phải là phần tử con của phần tử DOM khác không? Có bất kỳ phương pháp được xây dựng cho điều này? Ví dụ: một cái gì đó như:

if (element1.hasDescendant(element2)) 

hoặc là

if (element2.hasParent(element1)) 

Nếu không thì làm sao có ý tưởng này? Nó cũng cần phải là trình duyệt chéo. Tôi cũng nên đề cập rằng đứa trẻ có thể được lồng nhiều cấp dưới cha mẹ.


3
Bạn nên sử dụng stackoverflow.com/a/18234150/1868545
llange

Tôi tin rằng vì hiện nay, JS là một "tiêu chuẩn sống", câu trả lời được chấp nhận nên được kiểm tra lại để nêu phương pháp "conatins" là câu trả lời được chấp nhận.
DavidTaubmann

Câu trả lời:


219

Cập nhật: Bây giờ có một cách bản địa để đạt được điều này. Node.contains(). Đề cập trong bình luận và dưới đây câu trả lời là tốt.

Câu trả lời cũ:

Sử dụng parentNodetài sản nên làm việc. Nó cũng khá an toàn từ quan điểm đa trình duyệt. Nếu mối quan hệ được biết là sâu một cấp, bạn có thể kiểm tra nó đơn giản:

if (element2.parentNode == element1) { ... }

Nếu đứa trẻ có thể được lồng vào nhau một cách tùy tiện bên trong cha mẹ, bạn có thể sử dụng một chức năng tương tự như sau để kiểm tra mối quan hệ:

function isDescendant(parent, child) {
     var node = child.parentNode;
     while (node != null) {
         if (node == parent) {
             return true;
         }
         node = node.parentNode;
     }
     return false;
}

Cảm ơn câu trả lời của bạn, vấn đề là đứa trẻ có thể được lồng nhiều cấp dưới cha mẹ.
AJ.

@AJ: Tôi đã cập nhật câu trả lời của mình để bao gồm một giải pháp nên hoạt động cho việc lồng con vào sâu trong lòng cha mẹ.
Asaph

228
Nếu bây giờ có ai đến đây, bạn có thể sử dụng Node.contains ( developer.mozilla.org/en-US/docs/DOM/Node.contains ), đây là một chức năng riêng trong các trình duyệt hiện đại.
Adam Heath

2
@JohnCarrell Có Node.contains(mặc dù không có trang caniuse)
gcampbell

3
@Asaph Bạn có thể vui lòng cập nhật câu trả lời của bạn để bao gồm cái mới Node.containskhông? :)

355

Bạn nên sử dụng Node.contains, vì giờ đây nó là tiêu chuẩn và có sẵn trong tất cả các trình duyệt.

https://developer.mozilla.org/en-US/docs/Web/API/Node.contains


Phương thức Node.hasParent (cha mẹ) là không cần thiết nhưng sẽ là Node.prototype.hasParent = function (phần tử) {return Element.contains (this);};
llange

6
Có phải nó cũng được hỗ trợ trong trình duyệt di động? Các tài liệu mdn có dấu chấm hỏi cho Android, Safari, IE và Opera.
thetallweek

1
@thetallweek - Ít nhất hoạt động trên Android 7 của tôi.
Nhân sư

5
ít nhất bạn đã có thể thêm một ví dụ
Nino kopac

2
Đây là câu trả lời tốt nhưng ví dụ sẽ rất hay:var parent = document.getElementById('menu'); var allElements = document.getElementsByTagName('a'); if (parent.contains(allElements[i]) { alert('Link is inside meni'); }
baron_bartek

45

Tôi chỉ phải chia sẻ 'của tôi'.

Mặc dù về mặt khái niệm giống như câu trả lời của Asaph (được hưởng lợi từ cùng khả năng tương thích trình duyệt chéo, thậm chí IE6), nó nhỏ hơn rất nhiều và có ích khi kích thước ở mức cao và / hoặc khi không cần thiết thường xuyên.

function childOf(/*child node*/c, /*parent node*/p){ //returns boolean
  while((c=c.parentNode)&&c!==p); 
  return !!c; 
}

.. hoặc là một lớp lót ( chỉ 64 ký tự !):

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

jsfiddle ở đây .


Cách sử dụng:
childOf(child, parent) trả về booleantrue| false.

Giải thích:
while đánh giá miễn là điều kiện while đánh giátrue.
Các&&(AND) khai thác lợi nhuận boolean true / false này sau khi đánh giá tình hình bên trái tay và phía bên tay phải, nhưng chỉ nếu phía bên trái tay là sự thật ( left-hand && right-hand) .

Phía bên trái (của &&) là : (c=c.parentNode).
Đây đầu tiên sẽ giao parentNodecủa cđể crồi AND điều hành sẽ đánh giá kết quả cnhư một boolean.
parentNodetrả về nullnếu không còn cha mẹ và nullđược chuyển đổi thành false, vòng lặp while sẽ dừng chính xác khi không còn cha mẹ nữa.

Phía bên tay phải (của &&) là : c!==p.
Các !==toán tử so sánh là ' không chính xác bằng'. Vì vậy, nếu cha mẹ của đứa trẻ không phải là cha mẹ (bạn đã chỉ định) thì nó ước tính true, nhưng nếu cha mẹ của đứa trẻ cha mẹ thì nó sẽ đánh giá false.
Vì vậy, nếu c!==p đánh giá thành false, thì &&toán tử trả về falsekhi điều kiện while và vòng lặp while dừng lại. (Lưu ý không cần thiết trong một thời gian và đóng cửa; dấu chấm phẩy là bắt buộc.)

Vì vậy, khi vòng lặp while kết thúc, clà một nút (không phải null) khi nó tìm thấy cha mẹ HOẶC nó lànull (khi vòng lặp chạy đến hết mà không tìm thấy kết quả khớp).

Vì vậy chúng tôi chỉ đơn giản returnlà thực tế (quy đổi như giá trị boolean, thay vì nút) với: return !!c;: các !( NOTnhà điều hành) sẽ đảo ngược một giá trị boolean ( truetrở thành falsevà ngược lại).
!cchuyển đổi c(nút hoặc null) thành boolean trước khi nó có thể đảo ngược giá trị đó. Vì vậy, thêm một giây !( !!c) chuyển đổi sai này lại là true (đó là lý do tại sao một đôi !!thường được dùng để 'chuyển đổi bất cứ điều gì để boolean').


Bổ sung:
Phần thân / tải trọng của hàm nhỏ đến mức, tùy theo trường hợp (như khi nó không được sử dụng thường xuyên và chỉ xuất hiện một lần trong mã), người ta thậm chí có thể bỏ qua hàm (gói) và chỉ sử dụng vòng lặp while:

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

c=a; while((c=c.parentNode)&&c!==b); //c=!!c;

if(!!c){ //`if(c)` if `c=!!c;` was used after while-loop above
    //do stuff
}

thay vì:

var a=document.getElementById('child'),
    b=document.getElementById('parent'),
    c;

function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}

c=childOf(a, b);    

if(c){ 
    //do stuff
}

4
@SolomonUcko: So sánh đẳng thức nghiêm ngặt ( !==) có thể cải thiện tốc độ bằng cách làm cho trình biên dịch rõ ràng rằng nó có thể bỏ qua các bước chuyển đổi kiểm tra kiểu và tùy chọn sẽ xảy ra trong so sánh đẳng thức lỏng lẻo, do đó cải thiện tốc độ (bằng cách mô tả chính xác hơn những gì chúng ta muốn xảy ra, điều này cũng có lợi cho lập trình viên). Tôi dường như cũng nhớ lại từ khi tôi viết bài này, rằng so sánh lỏng lẻo ( !=) rất dễ bị lỗi hoặc hoàn toàn không hoạt động trong một số trình duyệt cũ hơn (tôi nghi ngờ đó là trong IE6, nhưng tôi đã quên ).
GitaarLAB

29

Một giải pháp khác không được đề cập:

Ví dụ ở đây

var parent = document.querySelector('.parent');

if (parent.querySelector('.child') !== null) {
    // .. it's a child
}

Không quan trọng là phần tử có phải là con trực tiếp hay không, nó sẽ hoạt động ở mọi độ sâu.


Ngoài ra, sử dụng .contains()phương pháp :

Ví dụ ở đây

var parent = document.querySelector('.parent'),
    child = document.querySelector('.child');

if (parent.contains(child)) {
    // .. it's a child
}

19

Hãy xem Node # soDocumentP vị trí .

function isDescendant(ancestor,descendant){
    return ancestor.compareDocumentPosition(descendant) & 
        Node.DOCUMENT_POSITION_CONTAINS;
}

function isAncestor(descendant,ancestor){
    return descendant.compareDocumentPosition(ancestor) & 
        Node.DOCUMENT_POSITION_CONTAINED_BY;
}

Các mối quan hệ khác bao gồm DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_PRECEDINGDOCUMENT_POSITION_FOLLOWING .

Không được hỗ trợ trong IE <= 8.


hấp dẫn! Điều này làm tôi nhớ đến một chức năng JS mà tôi đã phát triển vào năm 2003 ... Tôi đã mất vài ngày và nhận được sự giúp đỡ của một số nhà phát triển JS ... Thật đáng kinh ngạc (và đáng buồn) rằng ngày nay vẫn chưa có triển khai trình duyệt hoàn toàn kéo thả và phù hợp với đối tượng .
DavidTaubmann


2

Tôi đã bắt gặp một đoạn mã tuyệt vời để kiểm tra xem một phần tử có phải là phần tử con của phần tử khác hay không. Tôi phải sử dụng điều này bởi vì IE không hỗ trợ .containsphương thức phần tử. Hy vọng điều này sẽ giúp những người khác là tốt.

Dưới đây là chức năng:

function isChildOf(childObject, containerObject) {
  var returnValue = false;
  var currentObject;

  if (typeof containerObject === 'string') {
    containerObject = document.getElementById(containerObject);
  }
  if (typeof childObject === 'string') {
    childObject = document.getElementById(childObject);
  }

  currentObject = childObject.parentNode;

  while (currentObject !== undefined) {
    if (currentObject === document.body) {
      break;
    }

    if (currentObject.id == containerObject.id) {
      returnValue = true;
      break;
    }

    // Move up the hierarchy
    currentObject = currentObject.parentNode;
  }

  return returnValue;
}

Tôi thực sự đã thử mọi polyfill khác trên trang này bao gồm cả .contains và đây là cái duy nhất hoạt động. Cảm ơn!
protoEveachion

1

Hãy thử cái này:

x = document.getElementById("td35");
if (x.childElementCount > 0) {
    x = document.getElementById("LastRow");
    x.style.display = "block";
}
else {
    x = document.getElementById("LastRow");
    x.style.display = "none";
}

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.