Get next element with specific class of clicked el

2020-05-02 03:19发布

I am trying to get the the first element with a specific class which follow the element clicked with pure JS (no JQuery) in the following way but get el.nextSibling is not a function error. Initially I was using JQuery parents().next() but would like to do this with pure JS:

const togglers = document.querySelectorAll('.toggler');
//console.log(togglers);
togglers.forEach(function(el) {
  el.addEventListener('click', function(e) {
    //const content = el.innerHTML;
    //console.log(content);
    el.nextSibling('.folder-content').style.display = 'block';
  })
});
<div class="folder">
  <div class="toggler">Click me 1</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum
  </div>
</div>
<div class="folder">
  <div class="toggler">Click me 2</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum
  </div>
</div>

Any help would be appreciated :)

标签: javascript
3条回答
够拽才男人
2楼-- · 2020-05-02 03:50

You can add a while loop to go searching for the first nextSibling that matches your criteria.

edit: As @j08691 points out, if your real code only cares about elements and not other node types, you can use nextElementSibling.

const togglers = document.querySelectorAll('.toggler');
//console.log(togglers);
togglers.forEach(function(el) {
  el.addEventListener('click', function(e) {
    var nextSibling = el.nextSibling;
    while (nextSibling) {
        if (
            nextSibling.nodeType == Node.ELEMENT_NODE
         && nextSibling.classList.contains('folder-content')
        ) {
            nextSibling.style.display = 'block';
            break;
        }
        nextSibling = nextSibling.nextSibling;
    }
  })
});
<div class="folder">
  <div class="toggler">Click me 1</div>
  <div>not this</div>
  <div>not this</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum 1!
  </div>
  <div>not this</div>
  <div class="toggler">Click me 1.5</div>
  <div>not this</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum 1.5!
  </div>
  <div>not this</div>
  <div>not this</div>
</div>
<div class="folder">
  <div class="toggler">Click me 2</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum
  </div>
</div>
<div class="folder">
  <div class="toggler">Click me 3</div>
  <div>no folder content here!</div>
</div>

查看更多
Fickle 薄情
3楼-- · 2020-05-02 04:12

nextElement is a property, not a function, so you don't use () with it. That said, using nextSibling can give you white space content which you don't want. Instead you can use nextElementSibling:

el.nextElementSibling.style.display = 'block';

const togglers = document.querySelectorAll('.toggler');
//console.log(togglers);
togglers.forEach(function(el) {
  el.addEventListener('click', function(e) {
    //const content = el.innerHTML;
    //console.log(content);
    el.nextElementSibling.style.display = 'block';
  })
});
<div class="folder">
  <div class="toggler">Click me 1</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum
  </div>
</div>
<div class="folder">
  <div class="toggler">Click me 2</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum
  </div>
</div>

查看更多
冷血范
4楼-- · 2020-05-02 04:15

I was building this answer while the others were coming in and, in the interest of variety and neat DOM programming, here's another way to skin this cat:

Here is the initial code that you have provided with a call to a separate function to do what was requested(find the next sibling matching a specified query string)

const togglers = document.querySelectorAll('.toggler');

togglers.forEach(function(el, i) {
  el.addEventListener('click', function(e) {

    searchNextSiblings(el, ".folder-content", function(ele) {
      ele.style.display = "block";
    });
  })
});

You'll notice that the function I am providing is called searchNextSiblings and it takes three parameters:

  1. The Element that you would like to search from.
  2. The Query String you would like the found element to match.
  3. A function that receives the found element, and that you can use to manipulate it.

Here is the function itself:

function searchNextSiblings(ele, q, fn) {
    let flag = false;
    const nodeIterator = document.createNodeIterator(
  ele.parentNode, 
  NodeFilter.SHOW_ELEMENT, 
  function(node) {
        if (ele.isSameNode(node)) flag = true;
        if (!flag) return NodeFilter.FILTER_REJECT;
        else {
            if (node.matches(q)) {
                flag = false;
                return NodeFilter.FILTER_ACCEPT
            };
        }
    });
    let currentNode;
    while (currentNode = nodeIterator.nextNode()) {
        fn(currentNode);
    }
}

And here is the annotated version:

    function searchNextSiblings(ele, q, fn) {
// we want to search from the first Element provided
// to properly search we will set our crawler to begin
// from its parent node, and when we reach the first Element
// we will begin searching for the Query String
// in order to do this we declare a flag to False
// when we reach the first Element we will set it as True
// This will let us know when we can search for the Matching Query

    let flag = false;
    const nodeIterator = document.createNodeIterator(
      ele.parentNode, //root to search from
      NodeFilter.SHOW_ELEMENT, //set the iterator to search for elements
      function(node) { 
        if (ele.isSameNode(node)) flag = true;
//if we've found the first Element, set the flag to True
        if (!flag) return NodeFilter.FILTER_REJECT;
//if the flag is False, continue searching for first Element
        else {
//if we have found the first Element,
//we are now searching for the Element that Matches the Query
            if (node.matches(q)) {
//if we find a matching element
                flag = false;
//set the flag to false to stop the search
                return NodeFilter.FILTER_ACCEPT
//return the found node
            };
        }
    });
// the above declares the node iterator
// but does not start it up

    let currentNode;
    while (currentNode = nodeIterator.nextNode()) {
        fn(currentNode);
    }
//the above "starts up" the nodeIterator
}

const togglers = document.querySelectorAll('.toggler');
togglers.forEach(function(el, i) {
	el.addEventListener('click', function(e) {
		searchNextSiblings(el, ".folder-content", function(ele) {
			ele.style.display = "block";
		});
	})
});

function searchNextSiblings(ele, q, fn) {
	let flag = false;
	const nodeIterator = document.createNodeIterator(
  ele.parentNode, 
  NodeFilter.SHOW_ELEMENT, 
  function(node) {
		if (ele.isSameNode(node)) flag = true;
		if (!flag) return NodeFilter.FILTER_REJECT;
		else {
			if (node.matches(q)) {
				flag = false;
				return NodeFilter.FILTER_ACCEPT
			};
		}
	});
	let currentNode;
	while (currentNode = nodeIterator.nextNode()) {
		fn(currentNode);
	}
}
<div class="folder">
  <div class="toggler">Click me 1</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum
  </div>
</div>
<div class="folder">
  <div class="toggler">Click me 2</div>
  <div class="folder-content" style="display: none">
    Lorem ipsum
  </div>
</div>

查看更多
登录 后发表回答