在jQuery.find()中跳过选择器的递归?

Gar*_*orn 6 javascript recursion jquery traversal jquery-traversing

TL; DR:我如何得到像find()这样的动作,但阻止某个选择器的遍历(不是完全停止,只是跳过)?

解答: $(Any).find(Selector).not( $(Any).find(Mask).find(Selector) )

有许多真正伟大的答案,我希望我可以更多地分配赏金点数,也许我应该为这些中的一些做出50 pt奖励; p我选择Karl- AndréGagnon 's因为这个答案设法让findExclude不需要一条,稍长,一条线.虽然这使用了三个查找调用和一个重度不过滤器,但在大多数情况下,jQuery可以使用非常快速的实现来跳过大多数find()的遍历.

下面列出了特别好的答案:

falsarella:我的解决方案有很好的改进,findExclude(),在许多情况下都是最好的

Zbyszek:一种类似于falsarella的基于过滤器的解决方案,在效率方面也很出色

贾斯汀:一个完全不同但可管理和功能性的解决方案来解决问题

每一种都有其独特的优点,值得一提.

我需要完全下降到一个元素并比较选择器,将所有匹配的选择器作为数组返回,但是当遇到另一个选择器时跳过下降到树中.

选择路径图 编辑:用我网站上的一些替换原始代码示例

这是一个消息论坛,可能有回复消息组嵌套在任何消息中.
但请注意,我们不能使用消息或内容类,因为该脚本也用于论坛之外的其他组件.只InterfaceGroup,Interfacecontrols类是潜在有用的-并且优选地只是接口和控制.

与代码交互并在JS Fiddle中查看它,感谢Dave A,这里在查看JavaScript控制台时单击按钮,可以看到控件类每个级别的.Interface嵌套被绑定一个额外的时间.

Visual A,论坛布局结构:

    <li class="InterfaceGroup">
        <ul class="Interface Message" data-role="MessagePost" >
            <li class="instance"> ... condensed ... </li>
            <li class="InterfaceGroup"> ... condensed ...</li>
        </ul>
        <ul class="Interface Message" data-role="MessagePost" >
            <li class="instance"> ... condensed ... </li>
        </ul>
        <ul class="Interface Message" data-role="MessagePost" >
            <li class="instance"> ... condensed ... </li>
            <li class="InterfaceGroup"> ... condensed ...</li>
        </ul>

    </li>
Run Code Online (Sandbox Code Playgroud)

在每个内部<li class="InterfaceGroup">可以有相同结构的任意数量的重复(每个组是消息的线程)和/或更深的嵌套,例如..

    <li class="InterfaceGroup">

        <ul class="Interface Message" data-role="MessagePost" >
            <li class="instance"> ... condensed ... </li>
            <li class="InterfaceGroup">

                <ul class="Interface Message" data-role="MessagePost" >
                    <li class="instance"> ... condensed ... </li>
                    <li class="InterfaceGroup"> ... condensed ...</li>
                </ul>
            </li>
        </ul>
    </li>
Run Code Online (Sandbox Code Playgroud)

在每个内部都有可以出现<li class="instance"> ... </li>的另一个团队决定的任意位置,class="controls"并且应该绑定一个事件监听器.虽然这些包含消息,但是其他组件任意构造它们的标记,但是总是有.controls内部的.Interface,它们被收集到.InterfaceGroup.内部内容(对于论坛帖子)的复杂度降低的版本在下面以供参考.

Visual B,带控件类的消息内容:

<ul class="Interface Message" data-role="MessagePost" >
    <li class="instance">
      <ul class="profile"> ...condensed, nothing clickable...</ul>
      <ul class="contents">
        <li class="heading"><h3>Hi there!</h3></li>
        <li class="body"><article>TEST Message here</article></li>
        <li class="vote controls">
          <button class="up" data-role="VoteUp" ><i class="fa fa-caret-up"> </i><br/>1</button>
          <button class="down" data-role="VoteDown" >0<br/><i class="fa fa-caret-down"> </i></button>
        </li>
        <li class="social controls">
          <button class="reply-btn" data-role="ReplyButton" >Reply</button>
        </li>
      </ul>
    </li>
    <li class="InterfaceGroup" >    <!-- NESTING OCCURRED -->
      <ul class="Interface Message" data-role="MessagePost" >
          <li class="instance">... condensed ... </li>
          <li class="InterfaceGroup" >... condensed ... </li>
      </ul>
   </li>
</ul>
Run Code Online (Sandbox Code Playgroud)

我们只能结合是控制接口类中,instance可能会或可能不存在,但界面.事件冒泡到.controls元素并且具有对.Interface它们的引用..

所以我想 $('.Interface').each( bind to any .controls not inside a deeper .Interface )

这是棘手的部分,因为

  • .Interface .controls.control在.each()中多次选择相同的
  • .not('.Interface .Interface .controls')取消任何更深层次的嵌套控件

我怎么能用jQuery.find()或类似的jQuery方法呢?

我一直在考虑,也许,使用没有选择器的孩子可以工作,并且可以做同样的事情,如发现在引擎盖下,但我不太确定它实际上是或不会导致可怕的性能.仍然,一个有效的答案可以接受.儿童.

更新:最初我尝试使用伪造的例子来简洁,但希望看到一个论坛结构将有助于澄清问题,因为它们是自然嵌套的结构.下面我也发布部分javascript供参考,第二行的init函数是最重要的.

减少JavaScript部分:

var Interface=function()
{
    $elf=this;

    $elf.call=
    {
        init:function(Markup)
        {
            $elf.Interface = Markup;
            $elf.Controls = $(Markup).find('.controls').not('.Interface .controls');
            $elf.Controls.on('click mouseenter mouseleave', function(event){ $elf.call.events(event); });
            return $elf;
        },
        events:function(e)
        {
            var classlist = e.target.className.split(/\s+/), c=0, L=0;
            var role = $(e.target).data('role');

            if(e.type == 'click')
            {
                CurrentControl=$(e.target).closest('[data-role]')[0];
                role = $(CurrentControl).data('role');

                switch(role)
                {
                    case 'ReplyButton':console.log('Reply clicked'); break;
                    case 'VoteUp':console.log('Up vote clicked'); break;
                    case 'VoteDown':console.log('Down vote clicked'); break;
                    default: break;
                }
            }
        }
    }
};

$(document).ready( function()
{
    $('.Interface').each(function(instance, Markup)
    {
        Markup.Interface=new Interface().call.init(Markup);
    });
} );
Run Code Online (Sandbox Code Playgroud)

Kar*_*non 6

如果要在find中排除元素,可以使用非过滤器.例如,我已经采取了排除元素的功能,并使其更短:

$.fn.findExclude = function( Selector, Mask,){
    return this.find(Selector).not(this.find(Mask).find(Selector))
}
Run Code Online (Sandbox Code Playgroud)

现在,对你说实话,我并不完全明白你想要什么.但是,当我看看你的功能时,我看到了你想要做的事情.

无论如何,看看这个小提琴,结果与你的相同:http://jsfiddle.net/KX65p/8/