简体   繁体   English

Vanilla JavaScript 等效于 jQuery(...).parent().nextAll(selector)

[英]Vanilla JavaScript equivalent of jQuery(…).parent().nextAll(selector)

I'm trying to have a vanilla JavaScript selector (without using jQuery) to get the same selection as shown below:我正在尝试使用 vanilla JavaScript 选择器(不使用 jQuery)来获得如下所示的相同选择:

$('[data-automationid=pictureupload_1]').parent().nextAll('input[type=text]')

Can someone please help me?有人可以帮帮我吗? I've been struggling with it.我一直在挣扎。

There is no nextAll method in DOM as far as I know, so it is a bit tricky to do that without using jQuery.据我所知,DOM 中没有nextAll方法,因此在不使用 jQuery 的情况下这样做有点棘手。

We can use a generator to iterate and filter nextElementSibling like this:我们可以使用生成器来迭代和过滤nextElementSibling如下所示:

function* myNextAll(e, selector) {
   while (e = e.nextElementSibling) {
       if ( e.matches(selector) ) {
          yield e;
       }
   }
}

let e1 = document.querySelector("[data-automationid=pictureupload_1]").parentElement;

let siblings = [...myNextAll(e1, "input[type=text]")];

  • Use document.querySelector('[data-automationid=pictureupload_1]') to select the starting-node.使用document.querySelector('[data-automationid=pictureupload_1]')选择起始节点。
  • Get with parentElement.children all the siblings from the parent-node (including the parent itself).使用parentElement.children获取父节点中的所有兄弟节点(包括父节点本身)。
  • Iterate through the siblings until the parent-node is founded.遍历兄弟节点,直到建立父节点。
  • Look for all other siblings if they are INPUT-nodes and from type text (=1).查找所有其他兄弟节点,如果它们是 INPUT 节点并且来自文本类型 (=1)。
  • Collect them in an array.将它们收集在一个数组中。

For demonstration iterate over the result and change the background via test-class.为了演示迭代结果并通过测试类更改背景。

If you want try: https://jsfiddle.net/7p8wt4km/2/如果你想试试: https : //jsfiddle.net/7p8wt4km/2/

 let result = []; let par = document.querySelector('[data-automationid=pictureupload_1]').parentElement; let sibling = par.parentElement.children; let found = false; for (let i=0; i< sibling.length; i++) { if (!found && sibling[i] ===par) { found = true; continue; } else if (found) { let sib = sibling[i]; if (sib.nodeName !== 'INPUT' || sib.nodeType!= 1) continue; result.push(sib); } } result.forEach(el => { el.classList.add('test');});
 .test { background: green; }
 <div> <div> Sibling 0 </div> <div> Parent <div data-automationid='pictureupload_1'> pictureupload_1 </div> </div> <input type='text'> <div type='text'> Sibling 2 </div> <input type='test'> <input type='checkbox'> </div>

You can try my code get with index element您可以尝试使用我的代码获取索引元素

const getIndex = (node, groupNode) => {
    return [...groupNode].indexOf(node);
}

Element.prototype.nextAll = function(){
    var allChildren = this.parentNode.children;
    var index = getIndex(this, allChildren);
    allChildren = [...allChildren].filter((item) => {
        return getIndex(item, allChildren) > index;
    });
    return allChildren;
}

The normal jQuery selector function and the parent method should be clear:正常的jQuery选择器函数和parent方法应该是清楚的:

document.querySelector("[data-automationid=pictureupload_1]").parentNode

nextAll doesn't currently have a vanilla JavaScript equivalent, but we can make one out of native DOM methods. nextAll目前没有一个原生的 JavaScript 等价物,但我们可以用原生 DOM 方法制作一个。 There are two ways of approaching it:有两种方法可以接近它:

  1. Select all children first, then filter all matching siblings after a certain element, or首先选择所有子元素,然后在某个元素之后过滤所有匹配的兄弟元素,或者
  2. using loops.使用循环。

1. Select all children first, then filter all matching siblings after a certain element 1.先选择所有子元素,然后过滤某个元素后所有匹配的兄弟元素

Getting the set of siblings can be partially achieved with .parentNode.children .使用.parentNode.children可以部分实现获取兄弟.parentNode.children But don't worry about selecting the parent element itself, because filtering by DOM order is easy.但是不要担心选择父元素本身,因为按 DOM 顺序过滤很容易。 This uses Node.prototype.compareDocumentPosition and Element.prototype.matches .这使用Node.prototype.compareDocumentPositionElement.prototype.matches I've also included some optional chaining so that if parentReference === document , parentReference.parentNode.children won't throw an error.我还包含了一些可选的链接,这样如果parentReference === documentparentReference.parentNode.children不会抛出错误。 It defaults to an empty array, then.那么它默认为一个空数组。

const selectParentMatchingNextSiblings = (jQuerySelector, siblingSelector) => {
    const parentReference = document.querySelector(jQuerySelector).parentNode;
    
    return Array.from(parentReference.parentNode?.children ?? [])
      .filter((element) => parentReference.compareDocumentPosition(element) & Document.DOCUMENT_POSITION_FOLLOWING && element.matches(siblingSelector));
  };

selectParentMatchingNextSiblings("[data-automationid=pictureupload_1]", "input[type=text]");

Alternative way with Ranges范围的替代方法

The Range API can also be used for document order comparison. Range API还可用于文档顺序比较。

const selectParentMatchingNextSiblings = (jQuerySelector, siblingSelector) => {
    const parentReference = document.querySelector(jQuerySelector).parentNode,
      nextSiblings = document.createRange();
    
    nextSiblings.setStartAfter(parentReference);
    nextSiblings.setEndAfter(parentReference.parentNode?.lastElementChild ?? parentReference);
    
    return Array.from(parentReference.parentNode?.children ?? [])
      .filter((element) => nextSiblings.comparePoint(element, 0) === 0 && element.matches(siblingSelector));
  };

selectParentMatchingNextSiblings("[data-automationid=pictureupload_1]", "input[type=text]");

Note that this one won't work with "html" as the first selector.请注意,此选项不适用于"html"作为第一个选择器。

2. Using loops 2. 使用循环

const selectMatchingNextSiblings = (jQuerySelector, siblingSelector) => {
    const parentReference = document.querySelector(jQuerySelector).parentNode,
      result = [];
    let currentElement = parentReference.nextElementSibling;
    
    while(currentElement){
      if(currentElement.matches(siblingSelector)){
        result.push(currentElement);
      }
      
      currentElement = currentElement.nextElementSibling;
    }
    
    return result;
  };

selectParentMatchingNextSiblings("[data-automationid=pictureupload_1]", "input[type=text]");

This should be self-explanatory.这应该是不言自明的。 The options from the other answers are also fine.其他答案中的选项也很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM