Есть ли способ выбрать одноуровневые узлы?

105

По некоторым причинам производительности я пытаюсь найти способ выбрать только одноуровневые узлы выбранного узла.

Например,

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

Если я выбрал узел inner1, могу ли я получить доступ к его братьям и сестрам, inner2-4узлам?

кодирующий медведь
источник

Ответы:

143

Ну ... конечно ... просто обращайтесь к родителю, а затем к потомкам.

 node.parentNode.childNodes[]

или ... используя jQuery:

$('#innerId').siblings()

Изменить: Клетус, как всегда, вдохновляет. Я копал дальше. Вот как по сути jQuery получает братьев и сестер:

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
источник
23
Обратите внимание, что jquery.siblings () исключает текущий узел из набора результатов.
cletus
3
Что очень приятно!
cgp
1
Фактически эквивалент node.parentNode.childNodes [] в jquery - это действительно $ (node) .parent (). Children (), а не $ (node) .siblings (). Это может быть приятной функцией, но может и раздражать. Все зависит от того, чего вы хотите.
cletus
1
Вы захотите проверить узлы ELEMENT_NODE с помощью node.parentNode.childNodes, потому что он также выдаст вам текстовые узлы с пустым пространством.
seanmonstar
Ничего, я думаю, что это было глупо - извините за это (удалено)
cgp
102
var sibling = node.nextSibling;

Это вернет одного брата сразу после него, или null больше нет доступных братьев и сестер. Точно так же вы можете использовать previousSibling.

[Edit] Если подумать, это даст не следующий divтег, а пробел после узла. Кажется, лучше

var sibling = node.nextElementSibling;

Также существует файл previousElementSibling.

парвус
источник
1
next / previousElementSibling не поддерживается в IE8
Вадим
1
Начиная с IE9 это так. См. Также stackoverflow.com/questions/5197825/…
parvus
14

Быстрый:

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

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

Получите дочерние элементы родителя в виде массива, отфильтруйте этот элемент.

Редактировать:

И чтобы отфильтровать текстовые узлы (спасибо pmrotule ):

var siblings = n => [...n.parentElement.children].filter(c=>c.nodeType == 1 && c!=n)
круглый
источник
2
Хорошее решение. Хотя, я бы проверил nodeType, чтобы отбросить текстовый узел[ ...n.parentNode.children ].filter(c => c.nodeType == 1 && c != n)
pmrotule
Как бы вы изменили это для машинописного текста?
Ник Скоццаро,
10

С 2017 года:
простой ответ: element.nextElementSiblingдля получения правильного родственного элемента. также у вас есть element.previousElementSiblingдля предыдущего

отсюда довольно просто получить все следующие родственники

var n = element, ret = [];
while (n = n.nextElementSibling){
  ret.push(n)
}
return ret;
Pery Mimon
источник
Он должен вернуть всех братьев и сестер, а не только nextили previous. Указание точного перехода назад или вперед в этом случае мало помогает.
dvlden
4
почему нет. если вы сделаете следующий и предыдущий, вы сможете получить полную картину. это ответ, чтобы показать новый способ делать вещи. и поделиться чем-то с читателями. просто для того, чтобы перейти к родительскому элементу, перейти к каждому элементу и отфильтровать текущий, который может сделать каждый
pery mimon
6

Вы проверили метод "Sibling" в 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 проверяет, является ли элемент узлом html, а n! == исключает текущий элемент.

Я думаю, вы можете использовать ту же функцию, весь этот код кажется ванильным javascript.

Николас Рохо
источник
6

Есть несколько способов сделать это.

Любой из следующих вариантов подойдет.

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

К вашему сведению: кодовая база jQuery - отличный ресурс для наблюдения за Javascript класса A.

Вот отличный инструмент, который очень упрощенно раскрывает кодовую базу jQuery. http://james.padolsey.com/jquery/

аббат
источник
3

Вот как вы можете получить предыдущего, следующего и всех братьев и сестер (с обеих сторон):

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

Используйте document.querySelectorAll (), а также циклы и итерацию

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
источник
1

jQuery

$el.siblings();

Родной - последний, Edge13 +

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

Родной (альтернатива) - последняя версия, Edge13 +

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

Родной - IE10 +

Array.prototype.filter.call(el.parentNode.children, (child) =>
  child !== el
);
Хумоюн Ахмад
источник
0
var childNodeArray = document.getElementById('somethingOtherThanid').childNodes;
Громовержец
источник
window.document.documentElement.childNodes [1] .childNodes [4] взято
Thunderboltz
это вообще какое-то решение вопроса?
zahid9i
Это не решает проблему или, по крайней мере, недостаточно четко, чтобы быть полезным.
cdeszaq
0

1) Добавить выбранный класс к целевому элементу
2) Найти всех дочерних элементов родительского элемента, исключая целевой элемент
3) Удалить класс из целевого элемента

 <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

Следующая функция вернет массив, содержащий всех братьев и сестер данного элемента.

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

Просто передайте выбранный элемент в getSiblings()функцию как единственный параметр.

Сааббир
источник
-2
x1 = document.getElementById('outer')[0]
      .getElementsByTagName('ul')[1]
      .getElementsByTagName('li')[2];
x1.setAttribute("id", "buyOnlineLocationFix");
андре рай
источник