¿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?

codificación
fuente

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);
}
cgp
fuente
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.

parvus
fuente
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)
roundar
fuente
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;
pery mimon
fuente
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.

Nicolás Rojo
fuente
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/

abbotto
fuente
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);
}
Maciej Sitko
fuente
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>

Gildas.Tambo
fuente
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
);
Humoyun Ahmad
fuente
0
var childNodeArray = document.getElementById('somethingOtherThanid').childNodes;
Thunderboltz
fuente
window.document.documentElement.childNodes [1] .childNodes [4] recogido de howtocreate.co.uk/tutorials/javascript/dombasics
Thunderboltz
¿Es alguna solución a la pregunta?
zahid9i
Esto no resuelve el problema en cuestión, o al menos no lo suficientemente claro como para ser útil.
cdeszaq
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
    }
Manoj Yadav
fuente
-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.

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