如何查找当前所选对象的所有兄弟姐妹

时间:2010-12-07 16:09:03

标签: javascript unobtrusive-javascript

在javascript中查找所有nextSiblings和previousSiblings的完美方式是什么。我尝试了几种方法但没有得到准确的解决方案如果选择了任何元素,我需要得到所有下一个兄弟的长度,不包括空格,任何空格或换行符

此外,我不想为此使用jquery,我特意从java脚本中查找内容

请咨询

11 个答案:

答案 0 :(得分:22)

这对解决方案来说有点啰嗦,但允许您创建一个关于如何获得兄弟姐妹的过滤器。

有三个功能可以上一个,下一个,或全部。如果您需要更多地控制您想要收集的兄弟姐妹类型,这可以改善但是起点不错。认为可能值得补充。

<强> Working Example

获取所有下一个兄弟姐妹

//this will start from the current element and get all of the next siblings

function getNextSiblings(elem, filter) {
    var sibs = [];
    while (elem = elem.nextSibling) {
        if (elem.nodeType === 3) continue; // text node
        if (!filter || filter(elem)) sibs.push(elem);
    }
    return sibs;
}

获取所有兄弟姐妹

//this will start from the current element and get all the previous siblings

function getPreviousSiblings(elem, filter) {
    var sibs = [];
    while (elem = elem.previousSibling) {
        if (elem.nodeType === 3) continue; // text node
        if (!filter || filter(elem)) sibs.push(elem);
    }
    return sibs;
}

获取所有兄弟姐妹

//this will start from the first child of the current element's parent and get all the siblings

function getAllSiblings(elem, filter) {
    var sibs = [];
    elem = elem.parentNode.firstChild;
    do {
        if (elem.nodeType === 3) continue; // text node
        if (!filter || filter(elem)) sibs.push(elem);
    } while (elem = elem.nextSibling)
    return sibs;
}

要应用于上述功能的示例过滤器

// Example filter only counts divs and spans but could be made more complex
function exampleFilter(elem) {
    switch (elem.nodeName.toUpperCase()) {
        case 'DIV':
            return true;
        case 'SPAN':
            return true;
        default:
            return false;
    }
}

HTML和测试输出

HTML

<div id='test'>
    <div id='test2'>asdf</div>
    <br /> sdf
    <div>asdfasdf<span>asdf</span></div>
    <div>a</div>
    <span>a</span>
    <br />
    <div>d</div>
    <hr/>
</div>

的JavaScript

var elem;
elem = document.getElementById('test2');

//with filter alerts 4
alert( getNextSiblings( elem, exampleFilter ).length );

// no filter, alerts 7
elem = document.getElementById('test2');// put elem back to what it was
alert( getNextSiblings( elem ).length );

// alerts 0
elem = document.getElementById('test2');// put elem back to what it was
alert( getPreviousSiblings( elem, exampleFilter ).length );

// alerts 5
elem = document.getElementById('test2');// put elem back to what it was
alert( getAllSiblings( elem, exampleFilter ).length );

答案 1 :(得分:17)

我假设这发生在一个事件处理程序中,其中this是对你想要影响其兄弟的目标元素的引用。

如果没有,则需要进行调整。

var result = [],
    node = this.parentNode.firstChild;

while ( node ) {
    if ( node !== this && node.nodeType === Node.ELEMENT_NODE ) 
      result.push( node );
    node = node.nextElementSibling || node.nextSibling;
}

// result will contain all type 1 siblings of "this"

答案 2 :(得分:5)

这是使用ES6的一种非常简短的方法:

function getAllSiblings(element, parent) {
        const children = [...parent.children];
        return children.filter(child => child !== element);
    }

这将返回不是该元素的父节点的所有子节点。

答案 3 :(得分:4)

您可以获取元素父级的所有子级,并排除元素本身。

答案 4 :(得分:2)

这是@ subhaze答案的更新。

此代码使用matches DOM method supported in modern browsers

Demo

function matches(elem, filter) {
  if (elem && elem.nodeType === 1) {
    if (filter) {
      return elem.matches(filter);
    }
    return true;
  }
  return false;
}

// this will start from the current element and get all of
// the next siblings
function getNextSiblings(elem, filter) {
  var sibs = [];
  while (elem = elem.nextSibling) {
    if (matches(elem, filter)) {
      sibs.push(elem);
    }
  }
  return sibs;
}

// this will start from the current element and get all the
// previous siblings
function getPreviousSiblings(elem, filter) {
  var sibs = [];
  while (elem = elem.previousSibling) {
    if (matches(elem, filter)) {
      sibs.push(elem);
    }
  }
  return sibs;
}

// this will start from the first child of the current element's
// parent and get all the siblings
function getAllSiblings(elem, filter) {
  var sibs = [];
  elem = elem.parentNode.firstChild;
  while (elem = elem.nextSibling) {
    if (matches(elem, filter)) {
      sibs.push(elem);
    }
  } 
  return sibs;
}

使用以下功能:

var elem = document.querySelector('#test');

// find all the "div" and "span" siblings
var after = getNextSiblings(elem, 'div, span');

// find previous siblings with ".list-item" class
var index = getPreviousSiblings(elem, '.list-item');

// get all siblings with a title attribute
var allSibs = getAllSiblings(elem, '[title]');

答案 5 :(得分:2)

回到2017年:
也许有更好的答案,但那又好又干净

function sibiling(dom, query) {
   var doms = dom.parentElement.querySelectorAll(query);
   return [].slice.call(doms).filter( d => d != dom);
}

答案 6 :(得分:1)

此答案之前已发布here以回应类似问题。

有几种方法可以做到。

以下任一项都可以解决问题。

// 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代码库是观察A级Javascript的绝佳资源。

这是一个优秀的工具,以非常简化的方式显示jQuery代码库。 http://james.padolsey.com/jquery/

答案 7 :(得分:0)

这里只有我的两分钱,我做了几个函数来获得任何元素的所有主流和下一个兄弟。

const getPreviousAll = element => {
  const previousAllFound = [];
  const getPrevious = element => {
    if (element !== null) {
      previousAllFound.push(element);
      const previousFound = element.previousElementSibling;
      if (previousFound !== null) {
        getPrevious(previousFound);
      }
    }
  };
  getPrevious(element.previousElementSibling);
  return previousAllFound;
};
const getNextAll = element => {
  const target = element;
  const nextAllFound = [];
  const getAll = element => {
    if (element !== null) {
      nextAllFound.push(element);
      const nextFound = element.nextElementSibling;
      if (nextFound !== null) {
        getAll(nextFound);
      }
    }
  };
  getAll(element.nextElementSibling);
  return nextAllFound;
};

您只需使用getElementById可以获取的节点调用此函数。

答案 8 :(得分:0)

  

以前的所有兄弟姐妹

// jQuery (optional filter selector)
$el.prevAll($filter);

// Native (optional filter function)
function getPreviousSiblings(elem, filter) {
  var sibs = [];
  while (elem = elem.previousSibling) {
      if (elem.nodeType === 3) continue; // ignore text nodes
      if (!filter || filter(elem)) sibs.push(elem);
  }
  return sibs;
}
  

所有下一个兄弟姐妹

// jQuery (optional selector filter)
$el.nextAll($filter);

// Native (optional filter function)
function getNextSiblings(elem, filter) {
        var sibs = [];
        var nextElem = elem.parentNode.firstChild;
        do {
            if (nextElem.nodeType === 3) continue; // ignore text nodes
            if (nextElem === elem) continue; // ignore elem of target
            if (nextElem === elem.nextElementSibling) {
                if (!filter || filter(elem)) {
                    sibs.push(nextElem);
                    elem = nextElem;
                }
            }
        } while(nextElem = nextElem.nextSibling)
        return sibs;
    }

过滤器功能示例:

function exampleFilter(elem) {
  switch (elem.nodeName.toUpperCase()) {
    case 'DIV':
      return true;
    case 'SPAN':
      return true;
    default:
      return false;
  }
}

答案 9 :(得分:0)

这特别有助于您选择所选项目的所有同级

下面的这个实际上帮助我通过PARENT(唯一知道您兄弟姐妹的人不知道您父母身份的人)选择了所有SIBLINGS(最初不包括所选项目本身)。您唯一知道的是您的直子长兄,即 previousElementSibling 和直子的直子,即 nextElementSibling 。大声笑!

代码

const allSiblings = Array.from(YOUR_SELECTION.parentElement.children)
                         .filter(sibling => sibling.UNIQUE_PropertyName !== (YOUR_SELECTION.COMPARABLE/UNIQUE_PropertyName));

// You don't have to save in a variable if you don't want to

示例

HTML

<div id="mummy">
    <div id="baby_1">Samuel</div>
    <div id="baby_2">Dave</div>
    <div id="baby_3">Shaun</div>
    <div id="baby_4">Michael</div>
    <div id="baby_5" class="selected">Fazlullah</div>
    <div id="baby_6">Samson</div>
    <div id="baby_7">Bais</div>
<div>

JavaScript

// I have decide to use the Names of the children as my UNIQUE_Property, So i can get that with the .textContent propertyName 

const selected = document.querySelector('.selected'); // So with "Fazlullah" selected

const allSiblings = Array.from(selected.parentElement.children) // I got to know his mum (.parentElement), then the mum's children(.children)
                         .filter(sibling => sibling.textContent !== selected.textContent); // And this now get's me a list (actually an Array) of his siblings that he doesn't even know.

allSiblings.forEach(sibling => {
    console.log(sibling.textContent);
});

如果我决定使用子代“ id”,则我的链式过滤器方法应为:.filter(sibling => sibling.id !== selected.id);

请参见Demo

答案 10 :(得分:0)

使用 ES2015 spreadindexOf

的简单解决方案

const getSiblings = (elm, withTextNodes) => {
  if( !elm || !elm.parentNode ) return
  
  let siblings = [...elm.parentNode[withTextNodes ? 'childNodes' : 'children']],
      idx = siblings.indexOf(elm);
  
  siblings.previous = siblings.slice(0, idx)
  siblings.next = siblings.slice(idx + 1)
  
  return siblings
}

// Usage example:
const testElm = document.querySelector('em');
const testElmSiblings = getSiblings(testElm);

console.log(
  testElmSiblings.previous,
  testElmSiblings.next,
  testElmSiblings
)
<div></div>
text node 1
<a></a>
<p></p>
<em></em>
<main></main>
text node 2
<hr/>
<b></b>