$ .prevAll([selector])和$ .nextAll([selector])如何工作?

时间:2016-07-29 14:48:10

标签: jquery algorithm jquery-selectors

正如标题所说,我试图找出jQuery的.prevAll().nextAll()背后的逻辑(并在简单的JS中复制)。查看源代码并没有像我希望的那样有用。

重要的是要记住,prevNodes也可以嵌套在其他元素中。所以这不是选择兄弟姐妹的问题。

这是我到目前为止所提出的:

// args should be two selectors, source node and previous nodes
const prevAll = (...args) => {
  // select all the nodes that matches the two selectors
  let elements = document.querySelectorAll(args.join(', '));
  elements = Array.from(elements);

  // get index of the source node inside all elements
  const index = elements.indexOf(document.querySelector(args[0]));

  // return everything before that index
  if (index >= 0)
    return elements.slice(0, index);

  return [];
}

const prevNodes = prevAll('.start-node', '.prev-node')

测试



// args should be two selectors, source node and previous nodes
const prevAll = (...args) => {
  // select all the nodes that matches the two selectors
  let elements = document.querySelectorAll(args.join(', '));
  elements = Array.from(elements);

  // get index of the source node inside all elements
  const index = elements.indexOf(document.querySelector(args[0]));

  // return everything before that index
  if (index >= 0)
    return elements.slice(0, index);

  return [];
}

const prevNodes = prevAll('.start-node', '.prev-node')

console.log(prevNodes)

<div class="prev-node"></div>
<div class="prev-node"></div>
<div class="prev-node"></div>

<div class="wrapper">
  <div class="prev-node"></div> <!-- this will be included as well -->
</div>

<!-- start here -->
<div class="start-node"></div>

<div class="next-node"></div>
&#13;
&#13;
&#13;

由于很多原因,这显然不是完美的解决方案。我相信起始节点选择器应该是一个唯一的节点。否则这不会按预期工作。我可以将第一个参数作为真正的Element对象传递,但逻辑会更复杂。

关于如何处理此事的任何其他想法?

4 个答案:

答案 0 :(得分:1)

这只是prevAll(),但应该明白如何走另一条路(.nextElementSibling):)

let prevAll = (selector, restrictionSelector = "") => {
  let elements = Array.from(document.querySelectorAll(selector)),
    restrictedElements = restrictionSelector ? Array.from(document.querySelectorAll(restrictionSelector)) : [],
    result = [];

  elements.forEach((element) => {
    let prevElement = element.previousElementSibling;

    while (prevElement) {
      if (restrictedElements.length === 0 || restrictedElements.some((r) => r === prevElement)) {
        result.push(prevElement);
      }
      prevElement = prevElement.previousElementSibling;
    }
  });

  return result;
}

let test = prevAll("div.start-node");
console.log(test);

test = prevAll("div.start-node", "div.wrapper");
console.log(test);
<div class="prev-node"></div>
<div class="prev-node"></div>
<div class="prev-node"></div>
<div class="wrapper">
  <div class="prev-node"></div>
</div>

<!-- start here -->
<div class="start-node"></div>

<div class="next-node"></div>

答案 1 :(得分:0)

我在纯JS中可以想到的复制prevAll函数的唯一方法是通过选择器找到当前元素,选择该元素的第一个父元素并循环遍历子元素,只拉动具有相同元素的子节点节点名称作为您选择的元素。

示例(这是非常粗略的,不需要多个参数,如果你有一个包含多个结果的选择器,你也会遇到麻烦):

function prevAll(selector) {
    elements = document.querySelector(selector);
    var nodeType = elements.nodeName;
    var totalElements = elements.parentElement.childNodes;
    var re = [];
    for(i = 0; i < totalElements.length; i++) {
        if(totalElements[i].nodeName != nodeType) {
            continue;
        }    
        if(totalElements[i] == elements) {
            break;
        } else {
            re[re.length] = totalElements[i];
        }
    }
    return re;
}

最大的问题是jQuery可以处理元素的数组返回并且可以成功地将方法应用于该数组,JS主要是属性,并且在调整元素时不支持元素数组。

答案 2 :(得分:0)

我最近对使用没有jQuery的prevAll和nextAll有相同的要求。 这是我的方法:

function prevAll(element, result) {
  if(element.previousElementSibling){
    result.push(element.previousElementSibling);
    element=element.previousElementSibling;
    prevAll(element, result);
  }
  return result;
}

function nextAll(element, result) {
  if(element.nextElementSibling{
    result.push(element.nextElementSibling);
    element=element.nextElementSibling;
    nextAll(element,result);
  }
  return result;
}

通话:

    var element=document.querySelector('.class-name');//element has to be any dom element
    Array.prototype.forEach.call(prevAll(element, []), function (el) {
        //Do what you need to do with the previous elements here
    });
    Array.prototype.forEach.call(nextAll(element, []), function (el) {
        //Do what you need to do with the next elements here
    });

答案 3 :(得分:0)

这就是我在最近的项目中所做的:

const nextAll = (element) => {
    let siblingElements = []
    let elem = document.querySelector(element)

    while (elem.nextElementSibling) {
        siblingElements.push(elem.nextElementSibling)
        elem = elem.nextElementSibling
    }

    return siblingElements
 }

致电:

 nextAll('.layer')