Existe uma maneira de selecionar nós irmãos?

104

Por alguns motivos de desempenho, estou tentando encontrar uma maneira de selecionar apenas nós irmãos do nó selecionado.

Por exemplo,

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

Se eu selecionei o nó interno1, existe uma maneira de acessar seus irmãos, inner2-4nós?

urso codificador
fonte

Respostas:

141

Bem ... claro ... basta acessar o pai e depois os filhos.

 node.parentNode.childNodes[]

ou ... usando jQuery:

$('#innerId').siblings()

Edit: Cletus como sempre é inspirador. Eu cavei mais longe. É assim que o jQuery obtém irmãos essencialmente:

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
fonte
23
Observe que jquery.siblings () exclui o nó atual do conjunto de resultados.
cletus
3
O que é um recurso muito bom!
cgp
1
Na verdade, o equivalente a node.parentNode.childNodes [] em jquery é realmente $ (node) .parent (). Children () not $ (node) .siblings (). Pode ser um bom recurso, mas também pode ser irritante. Depende do que você quer.
cletus
1
Você vai querer verificar se há nós ELEMENT_NODE com node.parentNode.childNodes, porque ele também fornecerá nós de texto de espaço em branco.
seanmonstar
Nada, acho que foi uma besteira - desculpe por isso (removido)
cgp
100
var sibling = node.nextSibling;

Isso retornará o irmão imediatamente após ele, ou null, não há mais irmãos disponíveis. Da mesma forma, você pode usar previousSibling.

[Editar] Pensando bem, isso não fornecerá a próxima divtag, mas o espaço em branco após o nó. Melhor parece ser

var sibling = node.nextElementSibling;

Também existe um previousElementSibling .

parvus
fonte
1
next / previousElementSibling não é compatível com IE8
Vadim
1
A partir do IE9, sim. Veja também stackoverflow.com/questions/5197825/…
parvus
14

Rápido:

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

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

Obtenha os filhos do pai como um array, filtre este elemento.

Editar:

E para filtrar nós de texto (Obrigado pmrotule ):

var siblings = n => [...n.parentElement.children].filter(c=>c.nodeType == 1 && c!=n)
redondo
fonte
2
Ótima solução. Embora, eu verificaria o nodeType para descartar o nó de texto[ ...n.parentNode.children ].filter(c => c.nodeType == 1 && c != n)
pmrotule
Como você modificaria isso para o texto digitado?
Nic Scozzaro
10

A partir de 2017:
resposta direta: element.nextElementSiblingpara obter o irmão do elemento certo. também você tem element.previousElementSiblingpara o anterior

a partir daqui é muito simples obter todos os próximos irmãos

var n = element, ret = [];
while (n = n.nextElementSibling){
  ret.push(n)
}
return ret;
Pery Mimon
fonte
Deve retornar todos os irmãos, não apenas nextou previous. Especificar exatamente para trás ou para a frente não ajuda muito neste caso.
dvlden
4
Por que não. se você tirar o próximo e o anterior, poderá obter a imagem completa. essa resposta vem para mostrar uma nova maneira de fazer as coisas. e contribuir com algo para os leitores. apenas ir pai e ir cada elemento e filtrar o atual que todos podem fazer
pery mimon
6

você verificou o método "irmão" no jQuery?

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

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

        return r;
    }

o n.nodeType == 1 verifica se o elemento é um nó html e n! == exclui o elemento atual.

Acho que você pode usar a mesma função, todo esse código parece ser javascript vanilla.

Nicolas Rojo
fonte
6

Existem algumas maneiras de fazer isso.

Qualquer uma das opções a seguir deve resolver o problema.

// 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: A base de código jQuery é um grande recurso para observar Javascript de grau A.

Aqui está uma excelente ferramenta que revela a base de código jQuery de uma forma muito simplificada. http://james.padolsey.com/jquery/

abade
fonte
3

Veja como você poderia obter anterior, próximo e todos os irmãos (ambos os lados):

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
fonte
2

Use document.querySelectorAll () e Loops e iteração

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
fonte
1

jQuery

$el.siblings();

Native - mais recente, Edge13 +

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

Nativo (alternativo) - mais recente, Edge13 +

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

Nativo - IE10 +

Array.prototype.filter.call(el.parentNode.children, (child) =>
  child !== el
);
Humoyun Ahmad
fonte
0
var childNodeArray = document.getElementById('somethingOtherThanid').childNodes;
Thunderboltz
fonte
window.document.documentElement.childNodes [1] .childNodes [4] retirado de howtocreate.co.uk/tutorials/javascript/dombasics
Thunderboltz
é alguma solução para a questão?
zahid9i
Isso não resolve o problema em questão, ou pelo menos não é claro o suficiente para ser útil.
cdeszaq
0

1) Adicione a classe selecionada ao elemento de destino
2) Encontre todos os filhos do elemento pai, exceto o elemento de destino
3) Remova a classe do elemento de destino

 <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
fonte
-1

A função a seguir retornará um array contendo todos os irmãos do elemento fornecido.

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

Basta passar o elemento selecionado para a getSiblings()função como seu único parâmetro.

Saabbir
fonte
-2
x1 = document.getElementById('outer')[0]
      .getElementsByTagName('ul')[1]
      .getElementsByTagName('li')[2];
x1.setAttribute("id", "buyOnlineLocationFix");
andre paraíso
fonte