简体   繁体   中英

Find nearest element, not closest

I had an impression that closest() will give me nearest matching element as it suggest but I was wrong, it will give me nearest ancestor, so does parents() . So how can I get nearest element?

eg I have 2 div s as below

<div id="clickme">
    Click me
</div>
<div class="findme" style="display:none">
    Find me
</div>

what to do if I want to get .findme with reference with #clickme .

Can I do something like $('#click').helpfullFunctionThatGivesNearestElement('.findme') ?

Or do I need to scan entire DOM like $('findme') ? but there can be 100s of .findme then how will I find nearest to specific element?

Update

.findme can be anywhere in DOM.

This is how recursively traversing the DOM looks like.

I've implemented the function $.fn.nearest , as OP asumes to use jQuery, so it can be called with $('clickme').nearest('.findme');

The method will find multiple elements** (if they share the same distance from the starting node) by looking towards and backwards in every direction (parent, children, next and prev) by recursively searching through the nearest checked elements. It also avoids checking an element over and over again (ie the parent of multiple children is only checked once).

If you don't need a particular direction to be checked, ie children or prev you can just comment that part.

Some checks are made before the recursion is done. When the selector is not found in the DOM an empty jQuery element is returned, also when there is only one element found that found element is returned.

I haven't tested it's efficiency with a large HTML, it all depends on how far the desired element is located, and that is directly related to the complexity of the HTML structure. But for sure it is exponential, something close to O(n³) or O(n⁴).

Give it a try.

 $.fn.nearest = function(selector) { var allFound = $(selector); if (!allFound.length) // selector not found in the dom return $([]); if (allFound.length == 1) // found one elem only return allFound; else return nearestRec($(this), selector); function nearestRec(elems, selector) { if (elems.length == 0) return this; var selector = selector; var newList = [], found = $([]); $(elems).each(function(i, e) { var options = e[1] || {}; e = $($(e)[0]); // children if (!options.ignoreChildren) updateFound(e.children(), selector, newList, found, { ignoreParent: true }); // next if (!options.ignoreNext) updateFound(e.next(), selector, newList, found, { ignoreParent: true, ignorePrev: true }); // prev if (!options.ignorePrev) updateFound(e.prev(), selector, newList, found, { ignoreParent: true, ignoreNext: true }); // parent if (!options.ignoreParent) updateFound(e.parent(), selector, newList, found, { ignoreChildren: true }); }); return found.length && found || nearestRec(newList, selector); function updateFound(e, selector, newList, found, options) { e.each(function() { var el = $(this); if (el.is(selector)) { found.push(el); return; } newList.push([el, options]); }); } } }; $(function() { // multiple elems found, traverse dom $(".clickme").nearest(".findme").each(function() { $(this).addClass("found"); }); });
 div { padding: 5px 3px 5px 10px; border: 1px solid #666; background-color: #fff; margin: 3px; } .found { background-color: red; } .clickme { background-color: #37a; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="findme"> findme <div class="findme"> findme <div> &nbsp; <div> &nbsp; </div> <div> &nbsp; </div> <div class="clickme"> clickme <div> &nbsp; </div> <div> &nbsp; <div class="findme"> findme <div class="findme"> findme </div> </div> <div class="findme"> findme </div> </div> </div> <div> &nbsp; <div class="findme"> findme </div> </div> <div class="findme"> findme </div> </div> <div class="findme"> findme <div> &nbsp; </div> <div> &nbsp; </div> <div class="findme"> findme <div class="findme"> findme </div> </div> <div> &nbsp; </div> <div class="findme"> findme </div> </div> </div> </div>

jquery plugin:

(function( $ ){
    $.fn.nextElementInDom = function(selector, options) {
        var defaults = { stopAt : 'body' };
        options = $.extend(defaults, options);

        var parent = $(this).parent();
        var found = parent.find(selector + ":first");

        switch(true){
            case (found.length > 0):
                return found;
            case (parent.length === 0 || parent.is(options.stopAt)):
                return $([]);
            default:
                return parent.nextElementInDom(selector);
        }
    };
})( jQuery );

Usage:

 $('#clickme').nextElementInDom('.findme');

Instead of traversing the entire DOM tree, you can try to locate an element with reference to its enclosing parent.

<div>
<div id="clickme" onclick="$(this).parent().find('.findme').show();">
    Click me
</div>
<div class="findme" style="display:none">
    Find me
</div>
</div>

This will however work only if the element that you search has a same ancestral parent.

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