类似于 jQuery .closest() 但遍历后代?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8961770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 11:20:19  来源:igfitidea点击:

Similar to jQuery .closest() but traversing descendants?

jquery

提问by mamu

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

是否有类似于jQuery.closest()但用于遍历后代并仅返回最接近的函数的函数?

I know that there is .find()function, but it returns all possible matches, not closest.

我知道有.find()函数,但它返回所有可能的匹配项,而不是最接近的匹配项。

Edit:

编辑:

Here is definition of closest (at least for me):

这是最接近的定义(至少对我而言)

In first place all childrens are traversed, then each individuals childrens are traversed.

首先遍历所有孩子,然后遍历每个人的孩子。

In example given below id='2'is closest .closestdescendants of id="find-my-closest-descendant"

在下面给出的例子中id='2'是最近的.closest后代id="find-my-closest-descendant"

<div id="find-my-closest-descendant">
    <div>
        <div class="closest" Id='1'></div>
    </div>
    <div class="closest" Id='2'></div>
</div>

Please see JSfiddle link.

请参阅JSfiddle 链接

采纳答案by Rob W

According to your definition of closest, I've written the following plugin:

根据您对 的定义closest,我编写了以下插件:

(function($) {
    $.fn.closest_descendent = function(filter) {
        var $found = $(),
            $currentSet = this; // Current place
        while ($currentSet.length) {
            $found = $currentSet.filter(filter);
            if ($found.length) break;  // At least one match: break loop
            // Get all children of the current set
            $currentSet = $currentSet.children();
        }
        return $found.first(); // Return first match of the collection
    }    
})(jQuery);

回答by James

If by "closest" descendant you mean the first child then you can do:

如果“最近的”后代是指第一个孩子,那么您可以这样做:

$('#foo').find(':first');

Or:

或者:

$('#foo').children().first();

Or, to look for the first occurrence of a specific element, you could do:

或者,要查找特定元素的第一次出现,您可以执行以下操作:

$('#foo').find('.whatever').first();

Or:

或者:

$('#foo').find('.whatever:first');

Really though, we need a solid definition of what "closest descendant" means.

但实际上,我们需要对“最近的后代”的含义有一个明确的定义。

E.g.

例如

<div id="foo">
    <p>
        <span></span>
    </p>
    <span></span>
</div>

Which <span>would $('#foo').closestDescendent('span')return?

哪个<span>$('#foo').closestDescendent('span')回来?

回答by FishBasketGordo

You can use findwith the :firstselector:

您可以find:first选择器一起使用:

$('#parent').find('p:first');

The above line will find the first <p>element in the descendants of #parent.

上面的行将找到<p>的后代中的第一个元素#parent

回答by klawipo

What about this approach?

这种方法怎么样?

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

This "direct child" selector works for me.

这个“直接子”选择器对我有用。

回答by ccjmne

Pure JS solution (using ES6).

纯 JS 解决方案(使用 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                 == 
closestDescendant(
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 [
<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, 1, 2, 3, 4].map(x => document.querySelector(`#e${x}`)); console.log(closestDescendant(
Element.prototype.QuerySelector_BreadthFirst = function(selector) {
    let currentLayerElements = [...this.childNodes];
    while (currentLayerElements.length) {
        let firstMatchInLayer = currentLayerElements.find(a=>a.matches && a.matches(selector));
        if (firstMatchInLayer) return firstMatchInLayer;
        currentLayerElements = currentLayerElements.reduce((acc, item)=>acc.concat([...item.childNodes]), []);
    }
    return null;
};
, '.findme')); // console.log(closestDescendant(, '.findme')); // console.log(closestDescendant(, '.findme')); // console.log(closestDescendant(, '.findme')); // null
, '.findme') === ; closestDescendant(, '.findme') === ; closestDescendant(, '.findme') === ; closestDescendant(, '.findme') === null;
├── div == │ ├── div │ ├── div.findme == │ ├── div │ └── div ├── div.findme == │ ├── div │ └── div └── div == ├── div ├── div └── div
$("#find-my-closest-descendant").siblings('.closest:first');

jQuery.fn.extend( {

    closestChild_err : function( selector ) { // recursive, stack overflow when not found
        var found = this.children( selector ).first();
        if ( found.length == 0 ) {
            found = this.children().closestChild( selector ).first(); // check all children
        }
        return found;
    },

    closestChild : function( selector ) {
        var todo = this.children(); // start whith children, excluding this
        while ( todo.length > 0 ) {
            var found = todo.filter( selector );
            if ( found.length > 0 ) { // found closest: happy
                return found.first();
            } else {
                todo = todo.children();
            }
        }
        return $();
    },

});  
$.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;
};

回答by Venryx

In case someone's looking for a pure JS solution (using ES6 instead of jQuery), here's the one I use:

如果有人正在寻找纯 JS 解决方案(使用 ES6 而不是 jQuery),这是我使用的:

##代码##

回答by Jyoti watpade

You can just simply put,

你可以简单地说,

##代码##

回答by Jean Paul A.K.A el_vete

There is an excellent article that points out that what the OP requires can be achieved easily with closest [Geeks for Geeks]
1https://www.geeksforgeeks.org/jquery-closest-with-examples/

有一篇很棒的文章指出,使用最接近的 [Geeks for Geeks]
1 https://www.geeksforgeeks.org/jquery-closest-with-examples/可以轻松实现 OP 所需的内容

回答by Eelco

Even though it's an old topic I could not resist implementing my closestChild. Delivers the first found descendant with least traveling ( breath first ). One is recursive (personal favorite ), other using a todo list so without recursion as jQquery extensions.

即使这是一个老话题,我也无法抗拒实现我的最接近的孩子。以最少的旅行(先呼吸)交付第一个找到的后代。一种是递归的(个人最喜欢的),另一种是使用待办事项列表,因此没有作为 jQquery 扩展的递归。

Hope someone benefits.

希望有人受益。

Note : The recursive gets stack overflow, and I improved the other, now simular to previous answer given.

注意:递归得到堆栈溢出,我改进了另一个,现在类似于先前给出的答案。

##代码##

回答by cole

The following plugin returns the nth closest descendants.

以下插件返回第 n 个最近的后代。

##代码##