Czy istnieje sposób na wybranie węzłów rodzeństwa?

104

Z powodów związanych z wydajnością próbuję znaleźć sposób na wybranie tylko węzłów rodzeństwa wybranego węzła.

Na przykład,

<div id="outer">
  <div id="inner1"></div>
  <div id="inner2"></div>
  <div id="inner3"></div>
  <div id="inner4"></div>
</div>

Jeśli wybrałem węzeł inner1, czy jest sposób, aby uzyskać dostęp do jego rodzeństwa, inner2-4węzłów?

codingbear
źródło

Odpowiedzi:

141

Cóż ... jasne ... po prostu uzyskaj dostęp do rodzica, a potem do dzieci.

 node.parentNode.childNodes[]

lub ... używając jQuery:

$('#innerId').siblings()

Edycja: Cletus jak zawsze jest inspirujący. Kopałem dalej. W ten sposób jQuery zyskuje rodzeństwo:

function getChildren(n, skipMe){
    var r = [];
    for ( ; n; n = n.nextSibling ) 
       if ( n.nodeType == 1 && n != skipMe)
          r.push( n );        
    return r;
};

function getSiblings(n) {
    return getChildren(n.parentNode.firstChild, n);
}
cgp
źródło
23
Zauważ, że jquery.siblings () wyklucza bieżący węzeł z zestawu wyników.
cletus
3
To bardzo fajna funkcja!
cgp
1
Właściwie odpowiednikiem node.parentNode.childNodes [] w jquery jest tak naprawdę $ (node) .parent (). Children (), a nie $ (node) .siblings (). Może to być fajna funkcja, ale może też być denerwująca. To zależy od tego, czego chcesz.
cletus
1
Będziesz chciał sprawdzić węzły ELEMENT_NODE za pomocą node.parentNode.childNodes, ponieważ da ci to również węzły tekstowe spacji.
seanmonstar
Nic, myślę, że to była głupota - przepraszam za to (usunięte)
cgp
101
var sibling = node.nextSibling;

Spowoduje to zwrócenie rodzeństwa natychmiast po nim lub zerowanie, gdy rodzeństwo nie będzie już dostępne. Podobnie możesz użyć previousSibling.

[Edytuj] Po namyśle nie da to następnego divtagu, ale białą spację po węźle. Wydaje się, że lepiej

var sibling = node.nextElementSibling;

Istnieje również plik previousElementSibling.

parvus
źródło
1
next / previousElementSibling nie jest obsługiwany w IE8
Vadim
1
Począwszy od IE9 to jest. Zobacz także stackoverflow.com/questions/5197825/…
parvus
14

Szybki:

var siblings = n => [...n.parentElement.children].filter(c=>c!=n)

https://codepen.io/anon/pen/LLoyrP?editors=1011

Pobierz dzieci rodzica jako tablicę, odfiltruj ten element.

Edytować:

I odfiltrować węzły tekstowe (dzięki pmrotule ):

var siblings = n => [...n.parentElement.children].filter(c=>c.nodeType == 1 && c!=n)
okrągły
źródło
2
Niezłe rozwiązanie. Chociaż sprawdziłbym nodeType, aby odrzucić węzeł tekstowy[ ...n.parentNode.children ].filter(c => c.nodeType == 1 && c != n)
pmrotule
Jak zmodyfikowałbyś to dla maszynopisu?
Nic Scozzaro
10

Od 2017:
prosta odpowiedź: element.nextElementSiblingaby uzyskać odpowiedni element dla rodzeństwa. też masz element.previousElementSiblingna poprzedni

stąd łatwo jest uzyskać kolejne rodzeństwo

var n = element, ret = [];
while (n = n.nextElementSibling){
  ret.push(n)
}
return ret;
pery mimon
źródło
Powinien zwrócić całe rodzeństwo, nie tylko nextlub previous. Dokładne określenie ruchu wstecz lub do przodu nie pomaga w tym przypadku.
dvlden
4
Dlaczego nie. jeśli zrobisz następny i poprzedni, możesz uzyskać pełny obraz. to odpowiedź ukazuje nowy sposób robienia rzeczy. i wnieś coś do czytelników. po prostu przejść do rodzica i przejść do każdego elementu i przefiltrować bieżący, który każdy może zrobić
pery mimon
6

czy sprawdziłeś metodę „Sibling” w jQuery?

    sibling: function( n, elem ) {
        var r = [];

        for ( ; n; n = n.nextSibling ) {
            if ( n.nodeType === 1 && n !== elem ) {
                r.push( n );
            }
        }

        return r;
    }

n.nodeType == 1 sprawdza, czy element jest węzłem html i n! == wyklucza bieżący element.

Myślę, że możesz użyć tej samej funkcji, cały ten kod wydaje się być zwykłym javascriptem.

Nicolas Rojo
źródło
6

Można to zrobić na kilka sposobów.

Jedna z poniższych czynności powinna załatwić sprawę.

// METHOD A (ARRAY.FILTER, STRING.INDEXOF)
var siblings = function(node, children) {
    siblingList = children.filter(function(val) {
        return [node].indexOf(val) != -1;
    });
    return siblingList;
}

// METHOD B (FOR LOOP, IF STATEMENT, ARRAY.PUSH)
var siblings = function(node, children) {
    var siblingList = [];
    for (var n = children.length - 1; n >= 0; n--) {
        if (children[n] != node) {
            siblingList.push(children[n]);
        }  
    }
    return siblingList;
}

// METHOD C (STRING.INDEXOF, ARRAY.SPLICE)
var siblings = function(node, children) {
   siblingList = children;
   index = siblingList.indexOf(node);
   if(index != -1) {
       siblingList.splice(index, 1);
   }
   return siblingList;
}

FYI: Baza kodu jQuery jest świetnym źródłem do obserwacji Javascript klasy A.

Oto doskonałe narzędzie, które odsłania kod bazowy jQuery w bardzo uproszczony sposób. http://james.padolsey.com/jquery/

opat
źródło
3

Oto, jak możesz zdobyć poprzednie, następne i całe rodzeństwo (obie strony):

function prevSiblings(target) {
   var siblings = [], n = target;
   while(n = n.previousElementSibling) siblings.push(n);
   return siblings;
}

function nextSiblings(target) {
   var siblings = [], n = target;
   while(n = n.nextElementSibling) siblings.push(n);
   return siblings;
}

function siblings(target) {
    var prev = prevSiblings(target) || [],
        next = nexSiblings(target) || [];
    return prev.concat(next);
}
Maciej Sitko
źródło
2

Zastosowanie document.querySelectorAll () i pętli i iteracji

function sibblingOf(children,targetChild){
  var children = document.querySelectorAll(children);
  for(var i=0; i< children.length; i++){
    children[i].addEventListener("click", function(){
      for(var y=0; y<children.length;y++){children[y].classList.remove("target")}
      this.classList.add("target")
    }, false)
  }
}

sibblingOf("#outer >div","#inner2");
#outer >div:not(.target){color:red}
<div id="outer">
      <div id="inner1">Div 1 </div>
      <div id="inner2">Div 2 </div>
      <div id="inner3">Div 3 </div>
      <div id="inner4">Div 4 </div>
 </div>

Gildas.Tambo
źródło
1

jQuery

$el.siblings();

Native - najnowsze, Edge13 +

[...el.parentNode.children].filter((child) =>
  child !== el
);

Natywny (alternatywny) - najnowszy, Edge13 +

Array.from(el.parentNode.children).filter((child) =>
  child !== el
);

Natywny - IE10 +

Array.prototype.filter.call(el.parentNode.children, (child) =>
  child !== el
);
Humoyun Ahmad
źródło
0
var childNodeArray = document.getElementById('somethingOtherThanid').childNodes;
Thunderboltz
źródło
window.document.documentElement.childNodes [1] .childNodes [4] pobrane z howtocreate.co.uk/tutorials/javascript/dombasics
Thunderboltz
czy jest to w ogóle jakieś rozwiązanie tego pytania?
zahid9i
Nie rozwiązuje to obecnego problemu, a przynajmniej nie jest wystarczająco jasne, aby było przydatne.
cdeszaq
0

1) Dodaj wybraną klasę do elementu docelowego
2) Znajdź wszystkie dzieci elementu nadrzędnego z wyjątkiem elementu docelowego
3) Usuń klasę z elementu docelowego

 <div id = "outer">
            <div class="item" id="inner1">Div 1 </div>
            <div class="item" id="inner2">Div 2 </div>
            <div class="item" id="inner3">Div 3 </div>
            <div class="item" id="inner4">Div 4 </div>
           </div>



function getSiblings(target) {
    target.classList.add('selected');
    let siblings = document.querySelecttorAll('#outer .item:not(.currentlySelected)')
    target.classList.remove('selected'); 
return siblings
    }
Manoj Yadav
źródło
-1

Następująca funkcja zwróci tablicę zawierającą wszystkie elementy rodzeństwa danego elementu.

function getSiblings(elem) {
    return [...elem.parentNode.children].filter(item => item !== elem);
}

Po prostu przekaż wybrany element do getSiblings()funkcji jako jedyny parametr.

Saabbir
źródło
-2
x1 = document.getElementById('outer')[0]
      .getElementsByTagName('ul')[1]
      .getElementsByTagName('li')[2];
x1.setAttribute("id", "buyOnlineLocationFix");
Andre Raj
źródło