非贪婪 jquery 选择器

Non-greedy jquery selector

我正在尝试构建 jQuery 选择器以 html 元素与 class "widget" 以 "non-greedy" 方式且没有任何文档结构匹配假设。我的意思是:不匹配具有相同 class 的内部子元素,也不关心小部件元素是否是直接子元素。

我知道的唯一方法也是使用 .not() 选择器,例如:

$(".widget").not(".widget .widget");

但是这样选择器无法在小部件内容中再次找到 "subwidgets"。

例如,给定这个 html:

<div class="otherClass">
    <h1>Some title</h1>
    <p>Some text...</h1>
    <div class="widget" id="w100">
        <div>
            <h2>Some intermediate level...</h2>
            <div class="widget" id="w110">
                <h2>Some title</h2>
                <div class="widget" id="w111">
                    ...
                </div>
                <div class="widget" id="w112">
                    ...
                </div>
            </div>
        </div>
        <div class="widget" id="w120">
            <h2>Some title</h2>
            <div class="widget" id="w121">
                ...
            </div>
            <div class="widget" id="w122">
                ...
            </div>
        </div>
    </div>
</div>

假设我要构建的选择器存储在 selector 变量中,我希望这样:

var s0 = $(selector); // Matches div#w100 but not inner elements with "widget" class".
var s1 = $(selector, s0); // Matches div#w110 and div#w120
var s21 = $(selector, s1[0]); // Matches div#w111 and div#112
var s22 = $(selector, s1[1]); // Matches div#w121 and div#122

我的目标是基于应用于具有 "widget" 类的元素的小型控制器来实现一个简单的可嵌套小部件系统 s 和 data-xxx 属性中的其他参数来选择实际的小部件控制器和参数。但是,小部件必须是 le 在其 html 内容中展开其他子小部件。

使用$(".otherClass > .widget").

>代表"First-level children".

转念一想 可以考虑这是一个解决方案

https://jsfiddle.net/xejtj9gw/

基本上定义了一个函数

function $Flevel(selector,parent)
{
    var sol=$(parent).children(selector);
   return sol;  
}

访问一级子级。

所以选择器需要

var selector='div.widget';
var s0 = $Flevel(selector,'.otherClass');
var s1 = $Flevel(selector, s0); 
var s21 = $Flevel(selector, s1[0]); 
var s22 = $Flevel(selector, s1[1]);

您需要使用直接子选择器:

$(".otherClass > .widget")

您可以使用 $('.otherClass').children('.widget'),因为 children 仅匹配第一级。

这应该比像 .otherClass > .widget.

这样的裸 css 选择器稍微快一点

如果您想按照您描述的方式进行限制,则需要使用直接后代选择器 jQuery children()。 jQuery 上下文选择器默认情况下与 find() 相同,它将获得所有匹配的子元素:

api.jquery.com docs

Internally, selector context is implemented with the .find() method, so $( "span", this ) is equivalent to $( this ).find( "span" ).

因此,要使用集合的索引,您需要执行以下操作:

selector = '.otherClass > .widget';
var s0 = $(selector);
var s1 = $(s0).children('.widget');
var s22 = $(s1[0]).children('.widget');

或将直接后代与 nth-child() 对象组合:

var selector = {};
selector.s0 = '.otherClass > .widget';
selector.s1 = selector + ' > .widget';
selector.s22 = s1 + ':nth-child(0) > .widget';

var s22 = $(selector.s22);

我可能会像前者一样使用选择器。这是一个工作示例:

https://jsfiddle.net/udev4gzv/6/

selector = '.otherClass > .widget';

var s0 = $(selector); // Matches div#w100 but not inner elements with "widget" class".
var s1 = $(s0).children('.widget'); // Matches div#w110 and div#w120
var s21 = $(s1[0]).children('.widget'); // Matches div#w111 and div#112
var s22 = $(s1[1]).children('.widget'); // Matches div#w121 and div#122

$(document).ready(function(){
    $('#s0').html('s0 matches: ' + s0.map(function() { return this.id; }).get());
    $('#s1').html('s1 matches: ' + s1.map(function() { return this.id; }).get());
    $('#s21').html('s21 matches: ' + s21.map(function() { return this.id; }).get());
    $('#s22').html('s22 matches: ' + s22.map(function() { return this.id; }).get());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="otherClass">
    <h1>Some title</h1>
    <p>Some text...</p>
    <div class="widget" id="w100">
        <div class="widget" id="w110">
            <h2>Some title</h2>
            <div class="widget" id="w111">
               ...
            </div>
            <div class="widget" id="w112">
                ...
            </div>
        </div>
        <div class="widget" id="w120">
            <h2>Some title</h2>
            <div class="widget" id="w121">
                ...
            </div>
            <div class="widget" id="w122">
                ...
            </div>
        </div>
    </div>
</div>
<br />
<h3>results:</h3>
<div id="s0"></div>
<div id="s1"></div>
<div id="s21"></div>
<div id="s22"></div>

我对你的问题的解释与这里的其他人有所不同。在我看来,您想要的是从某个点遍历 DOM,搜索 .widget 但不在具有 class 的任何元素下方递归。因此,如果您这样做:

var tops = $( /* some selector here*/ );

您想要顶级小部件,如果您这样做了:

var next = $(tops[0]).find( /* some selector here*/ );

你想要第一个顶级小部件下面的第二级小部件,等等。

有一个插件可以做到这一点:

https://github.com/jstnjns/jquery-nearest

我冒昧在这里发布它的代码:

(function() {

  $.fn.nearest = function(selector) {
    var $found = $(),
        checkChildren = function(filter) {
          var $children = this.children()
              $collection = $();

          $children.each(function() {
            var $matches = $(this).filter(filter),
                $fails = $(this).not(filter);

            if($matches.length) { $found = $found.add($matches); }

            if($fails.length) { checkChildren.call($fails, filter); }
          });
        };

    checkChildren.call(this, selector);

    return $found;
  }

}());

你可以这样使用:

var tops = $(document).nearest(".widget");
var next = $(tops[0]).nearest(".widget");