Get next element with specific class of clicked element with pure js

前端 未结 3 2069
深忆病人
深忆病人 2021-01-24 04:06

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 fun

相关标签:
3条回答
  • 2021-01-24 04:36

    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>

    0 讨论(0)
  • 2021-01-24 04:36

    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>

    0 讨论(0)
  • 2021-01-24 04:42

    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>

    0 讨论(0)
提交回复
热议问题