¿Hay alguna forma de seleccionar nodos hermanos?


104

Por algunas razones de rendimiento, estoy tratando de encontrar una manera de seleccionar solo los nodos hermanos del nodo seleccionado.

Por ejemplo,

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

Si seleccioné el nodo inner1, ¿hay alguna forma de acceder a sus hermanos, inner2-4nodos?

Respuestas:


141

Bueno ... claro ... solo acceda al padre y luego a los hijos.

 node.parentNode.childNodes[]

o ... usando jQuery:

$('#innerId').siblings()

Editar: Cletus, como siempre, es inspirador. Cavé más. Así es como jQuery obtiene hermanos esencialmente:

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);
}

23
Tenga en cuenta que jquery.siblings () excluye el nodo actual del conjunto de resultados.
cletus

3
¡Qué característica muy buena!
cgp

1
En realidad, el equivalente de node.parentNode.childNodes [] en jquery es realmente $ (node) .parent (). Children () no $ (node) .siblings (). Puede ser una buena característica, pero también puede resultar molesta. Depende de lo que quieras.
cletus

1
Querrá verificar los nodos ELEMENT_NODE con node.parentNode.childNodes, porque también le dará nodos de texto de espacio en blanco.
seanmonstar

Nada, creo que fue un error - perdón por eso (eliminado)
cgp

100
var sibling = node.nextSibling;

Esto devolverá el hermano inmediatamente después, o nulo, no hay más hermanos disponibles. Asimismo, puede utilizar previousSibling.

[Editar] Pensándolo bien, esto no dará la siguiente divetiqueta, sino el espacio en blanco después del nodo. Mejor parece ser

var sibling = node.nextElementSibling;

También existe un previousElementSibling.


1
siguiente / anteriorElementSibling no es compatible con IE8
Vadim

1
A partir de IE9 lo es. Véase también 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

Obtenga los hijos de los padres como una matriz, filtre este elemento.

Editar:

Y para filtrar los nodos de texto (gracias pmrotule ):

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

2
Buena solucion. Aunque, buscaría nodeType para descartar el nodo de texto[ ...n.parentNode.children ].filter(c => c.nodeType == 1 && c != n)
pmrotule

¿Cómo modificaría esto para mecanografiar?
Nic Scozzaro

10

A partir de 2017:
respuesta sencilla: element.nextElementSiblingpara obtener el elemento hermano correcto. también lo tienes element.previousElementSiblingpara el anterior

a partir de aquí es bastante simple obtener toda la próxima sibiling

var n = element, ret = [];
while (n = n.nextElementSibling){
  ret.push(n)
}
return ret;

Debe devolver a todos los hermanos, no solo nexto previous. Especificar exactamente retroceder o avanzar no ayuda mucho en este caso.
dvlden

4
Por qué no. si toma la siguiente y la anterior, puede obtener la imagen completa. esa respuesta viene para mostrar una nueva forma de hacer las cosas. y aportar algo a los lectores. solo para ir padre e ir cada elemento y filtrar el actual que todos pueden hacer
pery mimon

6

¿Ha verificado el método "Sibling" en 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 comprueba si el elemento es un nodo html y n! == excluye el elemento actual.

Creo que puedes usar la misma función, todo ese código parece ser javascript de vainilla.


6

Hay varias formas de hacerlo.

Cualquiera de los siguientes debería funcionar.

// 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;
}

Para su información: el código base de jQuery es un gran recurso para observar Javascript de grado A.

Aquí hay una excelente herramienta que revela el código base de jQuery de una manera muy simplificada. http://james.padolsey.com/jquery/


3

Así es como puede obtener los hermanos anteriores, siguientes y todos los hermanos (ambos 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);
}

2

Utilice document.querySelectorAll () y Loops e iteración

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>


1

jQuery

$el.siblings();

Nativo - más reciente, Edge13 +

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

Nativo (alternativa) - más reciente, Edge13 +

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

Nativo: IE10 +

Array.prototype.filter.call(el.parentNode.children, (child) =>
  child !== el
);


0

1) Agregar la clase seleccionada al elemento de destino
2) Buscar todos los hijos del elemento principal excluyendo el elemento de destino
3) Eliminar la clase del 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
    }

-1

La siguiente función devolverá una matriz que contiene todos los hermanos del elemento dado.

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

Simplemente pase el elemento seleccionado a la getSiblings()función como su único parámetro.


-2
x1 = document.getElementById('outer')[0]
      .getElementsByTagName('ul')[1]
      .getElementsByTagName('li')[2];
x1.setAttribute("id", "buyOnlineLocationFix");
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.