Similar to jQuery .closest() but traversing descendants?

后端 未结 16 710
情书的邮戳
情书的邮戳 2020-12-07 15:13

Is there a function similar to jQuery .closest() but for traversing descendants and returning only closest ones?

I know that there is

相关标签:
16条回答
  • 2020-12-07 15:59

    The following plugin returns the nth closest descendants.

    $.fn.getNthClosestDescendants = function(n, type) {
      var closestMatches = [];
      var children = this.children();
    
      recursiveMatch(children);
    
      function recursiveMatch(children) {
        var matches = children.filter(type);
    
        if (
          matches.length &&
          closestMatches.length < n
        ) {
          var neededMatches = n - closestMatches.length;
          var matchesToAdd = matches.slice(0, neededMatches);
          matchesToAdd.each(function() {
            closestMatches.push(this);
          });
        }
    
        if (closestMatches.length < n) {
          var newChildren = children.children();
          recursiveMatch(newChildren);
        }
      }
    
      return closestMatches;
    };
    
    0 讨论(0)
  • 2020-12-07 15:59

    Pure JS solution (using ES6).

    export function closestDescendant(root, selector) {
      const elements = [root];
      let e;
      do { e = elements.shift(); } while (!e.matches(selector) && elements.push(...e.children));
      return e.matches(selector) ? e : null;
    }
    

    Example

    Considering the following structure:

    div                 == $0
    ├── div             == $1
    │   ├── div
    │   ├── div.findme  == $4
    │   ├── div
    │   └── div
    ├── div.findme      == $2
    │   ├── div
    │   └── div
    └── div             == $3
        ├── div
        ├── div
        └── div
    
    closestDescendant($0, '.findme') === $2;
    closestDescendant($1, '.findme') === $4;
    closestDescendant($2, '.findme') === $2;
    closestDescendant($3, '.findme') === null;
    

    function closestDescendant(root, selector) {
      const elements = [root];
      let e;
      do { e = elements.shift(); } while (!e.matches(selector) && elements.push(...e.children));
      return e.matches(selector) ? e : null;
    }
    
    const [$0, $1, $2, $3, $4] = [0, 1, 2, 3, 4].map(x => document.querySelector(`#e${x}`));
    
    console.log(closestDescendant($0, '.findme')); // $2
    console.log(closestDescendant($1, '.findme')); // $4
    console.log(closestDescendant($2, '.findme')); // $2
    console.log(closestDescendant($3, '.findme')); // null
    <div id="e0">
        <div id="e1">
            <div></div>
            <div id="e4" class="findme"></div>
            <div></div>
            <div></div>
        </div>
        <div id="e2" class="findme">
            <div></div>
            <div></div>
        </div>
        <div id="e3">
            <div></div>
            <div></div>
            <div></div>
        </div>
    </div>

    0 讨论(0)
  • 2020-12-07 16:01

    What about this approach?

    $('find-my-closest-descendant').find('> div');
    

    This "direct child" selector works for me.

    0 讨论(0)
  • 2020-12-07 16:05

    I was looking for a similar solution (I wanted all closest descendants, i.e. breadth first + all matches regardless of which level it exists), here's what I ended up doing:

    var item = $('#find-my-closest-descendant');
    item.find(".matching-descendant").filter(function () {
        var $this = $(this);
        return $this.parent().closest("#find-my-closest-descendant").is(item);
    }).each(function () {
        // Do what you want here
    });
    

    I hope this helps.

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