【问题标题】:jQuery .closest default contextjQuery .closest 默认上下文
【发布时间】:2016-04-07 09:47:54
【问题描述】:

jquery 的 closest 的文档说明如下:

.closest( 选择器 [, 上下文 ] )
...
上下文
类型:元素
一个 DOM 可以在其中找到匹配元素的元素。 如果没有上下文 传入的然后将使用 jQuery 集的上下文。

据我了解,粗体字表示这两个语句应该是等价的:

set.closest("a");

set.closest("a", set.context);

set 是一些 jquery 集。

然而,情况似乎并非如此:

var context = $("#inner")[0];
var set = $("#el", context);

// the set's context is correctly the "inner" element
set.text("context: " + set.context.id);

// if the set's context is used, this closest should match nothing, but it matches and sets the color
set.closest("#outer").css("color", "red");

// with the context explicitly set, the "outer" is not found and no background color is set
set.closest("#outer", set.context).css("background-color", "blue");
#outer{
  width: 100px;
  height: 100px;
  border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="outer">
  <div id="inner">
    <div id="el"></div>
  </div>
</div>

如您所见,当没有明确设置上下文时,似乎没有使用该集合的上下文,因为#outer 元素是由closest 找到的。明确设置时,#outer 正确找不到。

是文档不正确还是我遗漏了什么?

【问题讨论】:

  • 我猜文档是错误的。如果没有指定上下文,它看起来不像使用 jQuery 集的上下文。
  • 你为什么喜欢var set = $("#el", context);?根据阅读我得到的内容的文档,closest() 尝试将 selector 表达式匹配到祖先链上,直到找到匹配项。现在第二个参数closest()方法只是给它一个限制,直到它会继续寻找匹配。如果没有第二个参数,它将由 Jquery 决定 body 可能是最后一个父级。
  • 所以你的代码看起来不像是反对 Jquery 文档的正确示例。
  • 这有点令人困惑,因为 jQuery 的 closest() 并不总是使用上下文,它使用正则表达式来确定是否需要上下文,例如 /^[\x20\t\r\n\f]*[&gt;+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\([\x20\t\r\n\f]*((?:-\d)?\d*)[\x20\t\r\n\f]*\)|)(?=[^-]|$)/i,所以只需将其更改为 set.closest("#outer:first")使它使用上下文,不再匹配元素,而$('#el').closest("#outer:first") 仍然像它应该的那样匹配元素。
  • 我更喜欢使用 parents( selector ) 作为父元素,在您的代码中只需使用 id 选择器

标签: jquery jquery-context


【解决方案1】:

这显然是一个错误,而不是它的预期工作方式。

closest()的来源是

function (selectors, context) {
    var cur, 
        i = 0,
        l = this.length,
        matched = [],
        pos = rneedsContext.test(selectors) || typeof selectors !== "string" 
           ? 
           jQuery(selectors, context || this.context) 
           : 
           0;

    for (; i < l; i++) {
        for (cur = this[i]; cur && cur !== context; cur = cur.parentNode) {
            // Always skip document fragments
            if (cur.nodeType < 11 && (pos ? pos.index(cur) > -1 :

            // Don't pass non-elements to Sizzle
            cur.nodeType === 1 && jQuery.find.matchesSelector(cur, selectors))) {

                matched.push(cur);
                break;
            }
        }
    }

    return this.pushStack(matched.length > 1 ? jQuery.unique(matched) : matched);
}

值得注意的是pos的定义方式,它是要搜索最近父元素的集合,rneedsContext是正则表达式

/^[\x20\t\r\n\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\([\x20\t\r\n\f]*((?:-\d)?\d*)[\x20\t\r\n\f]*\)|)(?=[^-]|$)/i

如果传入的选择器与该正则表达式不匹配,则不使用任何上下文,pos 将等于 0,并且该集合中对 cur 的检查将被一起跳过,这看起来很奇怪.

快速测试显示

var reg = /^[\x20\t\r\n\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\([\x20\t\r\n\f]*((?:-\d)?\d*)[\x20\t\r\n\f]*\)|)(?=[^-]|$)/i;

reg.test('#outer');       // false, no context used
reg.test('#outer:first'); // true, context used
reg.test('#outer:eq(0)'); // true, context used

所以如果你添加一个伪选择器,它会突然使用上下文?

我怀疑这是否是预期的,这似乎是一件奇怪的事情,而且它肯定不会像文档所说的那样做。

【讨论】:

  • “最接近的()的来源是” 哪个版本的来源?见stackoverflow.com/questions/34580013/…
  • @guest271314 - 从 1.11.2 开始,但对于所有当前版本都相同
  • 两个 jsfiddles 都试过了吗?问题似乎至少已得到解决?虽然.text() 没有设置?或者,jsfiddle 没有加载最新的?为DOM元素集使用jQuery对象background-colorset.closest("#outer", $(set.context)).css("background-color", "blue");
  • 查看 2.1.4 的发行说明,closest 没有变化,查看 2.1.3 的源代码 closest,特别是 pos 变量,定义相同就像过去十个版本的 jQuery 一样。在 jsFiddle 中使用 2.1.4 进行测试似乎仍然存在同样的问题,所以我认为这是一个错误,感谢 James 发现它,这是一个奇怪的问题。
  • @adeneo 是的,我想我们意见一致。谢谢。我以为它坏了,但需要有人把它弹开。您的回答(和讨论)非常有帮助。我会提交一个错误报告。他们要么需要更改文档并从 pos 中删除 this.context,要么让非 pos 版本也使用 this.context。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 2019-11-21
  • 2019-07-28
  • 1970-01-01
  • 2017-08-15
  • 2016-12-24
相关资源
最近更新 更多