简体   繁体   中英

Javascript Traverse DOM until class is reached

I have HTML like:

<div id="hooray" class="section">
   <div>
      <div>
        <div id="click">click</div>
      </div>
   </div>
 </div>

When I click the div with class click , I want to move up the DOM until reaching the nearest section and grab the id .

With JQuery, I would use something like $().closest('div.section') , but how do I do that with pure Javascript without hardcoding in every parentNode ?

var node = document.getElementById('click').parentNode.parentNode....etc

You can just walk up the parent chain looking for an ancestor with the proper class. This version of the code allows there to be other class names on the object of interest so the code can be used more flexibly:

function hasClass(elem, cls) {
    var str = " " + elem.className + " ";
    var testCls = " " + cls + " ";
    return(str.indexOf(testCls) != -1) ;
}

function closest(el, cls) {
    while (el  && el !== document) {
        if (hasClass(el, cls)) return el;
        el = el.parentNode;
    }
    return null;
}

So, from your click handler, you can just do:

var id;
var target = closest(this, "section");
if (target) {
    id = target.id;
    // do whatever you want with the id
}

Working demo: http://jsfiddle.net/jfriend00/6V7HG/


FYI, a version of this code that can take any arbitrary selector is much, much more complicated as you essentially have to create a CSS selector parser and then evaluate if a given object matches all the requirements in that selector. That is probably way more work than you would want to do for this particular operation.

Usually, you're not looking up a chain for an id because you can just get the element with that id directly so I've offered a version that works with a class name. Other versions (like one that matched an attribute) could also be written.

This version is a little more generic than your particular question (returning the target element rather than the target id) which allows you to use it in more circumstances. If you really just want a function that returns the target id, that can be done like this:

function closest(el, cls) {
    while (el  && el !== document) {
        if (hasClass(el, cls)) return el.id;
        el = el.parentNode;
    }
    return null;
}

There are n number of ways to do this, you may try this one:

document.getElementById('click').onclick = function(e) {
    e = e || window.event;
    var el = e.target || e.srcElement;
    if (el = el.parentNode) do { //its an inverse loop
        var cls = el.className;
        if (cls) {
            cls = cls.split(" ");
            if (-1 !== cls.indexOf("section")) {
                console.log("here it is: ");
                console.log(el);
                break;
            }
        }
    } while (el = el.parentNode); //its assignment
    if (!el) {
        console.log('not found !');
    }
    console.log('end..');
};

You can just use Element.closest() :

let closestElement = document.getElementById('click').closest('.section');

Here is a snippet to show it in action:

 console.log(document.getElementById('click').closest('.section').id); 
 <div id="hooray" class="section"> <div> <div> <div id="click">click</div> </div> </div> </div> 

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