简体   繁体   中英

How to traverse DOM to find the last ancestor with specific attribute in Javascript?

Here is my sample HTML:

<div id="parent1" data-attribute="parent">
  <div id="child2" data-attribute="child">
    <div id="grandchild4" data-attribute="child">
    </div>
  </div>
</div>
<div id="parent2" data-attribute="parent">
  <div id="child3" data-attribute="child">
    <div id="grandchild1" data-attribute="parent">
      <div id="item1"></div>
    </div>
  </div>
  <div id="child4" data-attribute="parent">
    <div id="grandchild2" data-attribute="child">
      <div id="grandchild3" data-attribute="parent">
        <div id="item2" data-attribute="child">
          <div id="sub1" data-attribute="child">
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

If the current element I'm performing query selection on is sub1 , how do I find the last ancestor with data-attribute="parent" ? In this case, the expected result should be parent2 .

I know closest() will return the first match which would be grandchild3 , but is there like a selector to find the final ancestor? Querying by id is not option, since my id's are dynamically created.

First, to find all the ancestors, you can combine two conditions [data-attribute="parent"] and [id^="parent"] . More on wildcard selectors

$('div[id^="parent"][data-attribute="parent"]')

Now, once you have all the ancestors, the last() should give you the immediate one. Please find the snippet below

 console.log($('div[id^="parent"][data-attribute="parent"]').last().attr('id'))
 <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> <div id="parent1" data-attribute="parent"> <div id="child2" data-attribute="child"> <div id="grandchild4" data-attribute="child"> grandchild4 </div> </div> </div> <div id="parent2" data-attribute="parent"> <div id="child3" data-attribute="child"> <div id="grandchild1" data-attribute="parent"> grandchild1 <div id="item1">item1</div> </div> </div> <div id="child4" data-attribute="parent"> <div id="grandchild2" data-attribute="child"> <div id="grandchild3" data-attribute="parent"> grandchild3 <div id="item2" data-attribute="child"> item2 <div id="sub1" data-attribute="child"> sub1 </div> </div> </div> </div> </div> </div>

You can create your own version of closest which will give you the last ancestor of the type you require. If you're using jQuery:

 $.fn.extend({ closestTop: function(selection) { var el = this; var lastKnown = null; do { lastKnown = el; var guess = $(el).parent().length && $(el).parent().closest(selection || ''); el = guess && guess.length && guess.get(0) || null; } while (el;= null); return $(lastKnown); } }). console.log($('#sub1').closestTop('[data-attribute=parent]'))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div id="parent1" data-attribute="parent"> <div id="child2" data-attribute="child"> <div id="grandchild4" data-attribute="child"> </div> </div> </div> <div id="parent2" data-attribute="parent"> <div id="child3" data-attribute="child"> <div id="grandchild1" data-attribute="parent"> <div id="item1"></div> </div> </div> <div id="child4" data-attribute="parent"> <div id="grandchild2" data-attribute="child"> <div id="grandchild3" data-attribute="parent"> <div id="item2" data-attribute="child"> <div id="sub1" data-attribute="child"> </div> </div> </div> </div> </div> </div>

You could write an XPath expression and evaluate that.

 const element = document.querySelector('#sub1'); const xpath = 'ancestor::*[@data-attribute="parent"][last()]'; const result = document.evaluate(xpath, element, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; console.log(result);
 <div id="parent1" data-attribute="parent"> <div id="child2" data-attribute="child"> <div id="grandchild4" data-attribute="child"> </div> </div> </div> <div id="parent2" data-attribute="parent"> <div id="child3" data-attribute="child"> <div id="grandchild1" data-attribute="parent"> <div id="item1"></div> </div> </div> <div id="child4" data-attribute="parent"> <div id="grandchild2" data-attribute="child"> <div id="grandchild3" data-attribute="parent"> <div id="item2" data-attribute="child"> <div id="sub1" data-attribute="child"> </div> </div> </div> </div> </div> </div>

It' right???

document.getElementById("sub1").addEventListener("click", function(){

  let ancester = this.parentElement;
  let flag = ancester.getAttribute("data-attribute");

  while(flag !== "parent") {
    ancester = ancester.parentElement;
    flag = ancester.getAttribute("data-attribute");
  }

  console.log(ancester);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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