选择Dom元素范围

时间:2016-06-14 19:50:32

标签: javascript html css

我尝试选择一系列dom元素,从elementelement。这在JQuery中可以实现:(Source

$('#id').nextUntil('#id2').andSelf().add('#id2')

我试图仅使用JavaScript实现这一目标。

这是我尝试过的,但我得到了一个无限循环:

function prevRange(element, prevTill) {
    var result = [];

    while (element !== prevTill)
        result.push(element);
    return result;
}

JSFiddle



var wrapper = document.getElementById('wrapper'),
  wrapperChildren = wrapper.children;

console.log(prevRange(wrapperChildren[2], wrapperChildren[0]));

function prevRange(element, prevTill) {
  var result = [];

  /*while (element !== prevTill)
      result.push(element);*/
  return result;
}

<ul id="wrapper">
  <li class="inner">I'm #01</li>
  <li class="inner">I'm #02</li>
  <li class="inner">I'm #03</li>
  <li class="inner">I'm #04</li>
</ul>
&#13;
&#13;
&#13;

9 个答案:

答案 0 :(得分:1)

使用Element.previousElementSibling

var wrapper = document.getElementById('wrapper'),
  wrapperChildren = wrapper.children;

console.log(prevRange(wrapperChildren[2], wrapperChildren[0]));

function prevRange(element, prevTill) {
  var result = [element];

  while (element && element !== prevTill) {
    element = element.previousElementSibling;
    result.push(element);
  }

  return result;
}
<ul id="wrapper">
  <li class="inner">I'm #01</li>
  <li class="inner">I'm #02</li>
  <li class="inner">I'm #03</li>
  <li class="inner">I'm #04</li>
</ul>

答案 1 :(得分:1)

您的变量elementprevTill永远不会在while循环中更改。因此,当您第一次进入element循环时,如果prevTillwhile不相等,那么它们将永远不会出现,并且您的while循环将永远不会执行。

另外,你没有传入你试图迭代的元素数组并得到一个子集。

我会修改你的函数来接受你想要获得子集的元素数组,以及你想要的子集的起始和结束索引,然后你可以遍历{{1}中的数组。 }循环。

while
var wrapper = document.getElementById('wrapper'),
  wrapperChildren = wrapper.children;

console.log(prevRange(wrapperChildren, 0, 2));

function prevRange(array, start, end) {
  var result = [];

  var curr = start;

  while (curr <= end) {
    result.push(array[curr]);
    curr++;
  }

  return result;
}

答案 2 :(得分:0)

您不会迭代这些元素。 element永远不会等于prevTill因为你永远不会改变元素。如果您传递了元素子元素的数组,并使用for循环遍历它所需的范围,该怎么办?所以你要传递元素数组,你想要的第一个孩子的最小索引,以及你想要的最后一个孩子的最大索引。

答案 3 :(得分:0)

你不想这样做:

while (element !== null && element !== prevTill)
{
    result.push(element);
    element = element.previousElementSibling;
}

更新了fiddle

答案 4 :(得分:0)

已经有很多答案,但我已经为我认为你想要实现的目标实施了一个全面的解决方案。

    #!/usr/bin/python
print "Content-type: text/plain\r\n\r\n",
print "Hello world" 

答案 5 :(得分:0)

您必须迭代元素以避免无限循环。工作代码可能如下所示:

function prevRange(element, prevTill) {
    var result = [];
    if(element === prevTill){
       result.push(element);
       return result;
    }
    var siblings = element.parentNode.children;//prevTill is expected among siblings
    var startSelection = false;
    for(var i=0,ch;ch=siblings[i];++i){//iterate siblings
    if(ch === element || ch === prevTill){//no matter which go first
       result.push(ch);
       startSelection = !startSelection;//start/stop
    }
    else if(startSelection)
       result.push(ch);
    }

    /*while (element !== prevTill) this is your code
        result.push(element);*/
    return result;
}

答案 6 :(得分:0)

有几种方法可以做到这一点......我喜欢Nikhil的倒退回答,你可以用nextSibling属性做同样的事情。

我个人曾经遇到过下一次和之前的问题(特别是IE和Edge,YAY MS !!)

这是另一个非常简单的替代方案,但不依赖于DOM next / prev。

var wrapper = document.getElementById('wrapper'),
    wrapperChildren = wrapper.children;

console.log(stopWhen(wrapperChildren[0],wrapperChildren[2]));

function stopWhen(start,end){
    var results = new Array()
        ,parent = start.parentElement
      ,startPos = Array.prototype.indexOf.call(parent.childNodes, start)-2
      ,endPos = Array.prototype.indexOf.call(parent.childNodes, end)-2;
      for(var i=startPos; i < endPos; i++){    
        if(parent.children[i] != null){
            results.push(parent.children[i]);
        }
      }
      return results;
}

分叉fiddle

答案 7 :(得分:0)

合并数组原型sliceindexOf方法。

getRangeElements(
  document.getElementById('wrapper'), // parent
  document.getElementById('li1'),     // start
  document.getElementById('li3')      // end
)

function getRangeElements (parent, start, end) {
  var children = parent.children
  return [].slice.call(
    children, 
    [].indexOf.call(children, start),
    [].indexOf.call(children, end) + 1
  )
}

ChildNodes本身并不具有数组方法,因此使用call方法来应用该功能。一旦childNodes可以被视为数组元素,那么首先得到indexOf子元素,然后slice你正在寻找的范围。

假设:

<ul id="wrapper">
  <li class="inner" id="li1">I'm #01</li>
  <li class="inner" id="li2">I'm #02</li>
  <li class="inner" id="li3">I'm #03</li>
  <li class="inner" id="li4">I'm #04</li>
</ul>

...返回:

[li#li1.inner, li#li2.inner, li#li3.inner]

JSFiddle example

答案 8 :(得分:0)

您可以创建一个 TreeWalker 来为您执行此操作:

&#13;
&#13;
var wrapper = document.getElementById('wrapper');
var wrapperChildren = wrapper.children;

function getElementRange(rangeRoot, elementStart, elementEnd) {
  var result = [];
  var itr = document.createTreeWalker(
    rangeRoot,
    NodeFilter.SHOW_ELEMENT,
    null, // no filter
    false);
  itr.currentNode = elementStart;

  do {
    result.push(itr.currentNode);
  } while(itr.currentNode !== elementEnd && itr.nextSibling());

  return result;
}

console.log(getElementRange(wrapper, wrapperChildren[0], wrapperChildren[2]));
&#13;
<ul id="wrapper">
  <li class="inner">I'm #01</li>
  <li class="inner">I'm #02</li>
  <li class="inner">I'm #03</li>
  <li class="inner">I'm #04</li>
</ul>
&#13;
&#13;
&#13;

结帐This link to MDN 有关创建TreeWalkers的更多信息

我还建议您了解TreeWalker interface object

希望这有帮助。

*编辑 - 以下是支持双向范围的示例:

&#13;
&#13;
var wrapper = document.getElementById('wrapper');
var wrapperChildren = wrapper.children;

function getElementRange(elementStart, elementEnd) {
  var result = [];
  var rootNode;
  var indexStart;
  var indexEnd;
  
  rootNode = elementStart.parentNode;
  if(rootNode !== elementEnd.parentNode){
      return console.log("Cannot getElementRange, elements are not siblings");
  }
  
  //Get direction to traverse nodes
  indexStart = Array.prototype.indexOf.call(rootNode.childNodes, elementStart);
  indexEnd = Array.prototype.indexOf.call(rootNode.childNodes, elementEnd);

  var itr = document.createTreeWalker(
    rootNode,
    NodeFilter.SHOW_ELEMENT,
    null, // no filter
    false);
  itr.currentNode = elementStart;
  var iterateMethod = indexStart < indexEnd ? 'nextSibling' : 'previousSibling';
  do {
    result.push(itr.currentNode);
  } while(itr.currentNode !== elementEnd && itr[iterateMethod]());
  
  return result;
}

console.log(getElementRange(wrapperChildren[1], wrapperChildren[3]));
console.log(getElementRange(wrapperChildren[3], wrapperChildren[1]));
&#13;
<ul id="wrapper">
  <li class="inner">I'm #01</li>
  <li class="inner">I'm #02</li>
  <li class="inner">I'm #03</li>
  <li class="inner">I'm #04</li>
</ul>
&#13;
&#13;
&#13;