我有类似的要求(基本上使用单个字符串选择器在 DOM 中向上然后向下搜索),在深入研究选择器的工作原理后,我发现这对于普通选择器是不可能的,因为选择器元素的评估是 从右到左,而您需要从左到右 才能使您的建议发挥作用。我能够制作一个自定义选择器,它可以有一个:this 引用,它可以让你进行类似的搜索,包括:has(:this)。我在Is it possible to create custom jQuery selectors that navigate ancestors? e.g. a :closest or :parents selector这里重复了我的回答
基于大量的 cmets,以及关于为什么这是不可能的的详细解释,我突然想到,我想要的目标可以通过 $(document).find() 来实现,但有一些 目标元素。也就是说,在选择器中以某种方式定位原始查询元素。
为此,我想出了以下:this 选择器,它的工作原理是这样的(没有双关语):
// Find all labels under .level3 classes that have the .starthere class beneath them
$('.starthere').findThis('.level3:has(:this) .label')
这使我们现在可以有效地在单个选择器字符串中向上搜索 DOM,然后向下搜索到相邻的分支! 即它执行与此相同的工作(但在单个选择器中):
$('.starthere').parents('.level3').find('.label')
步骤:
1 - 添加一个新的jQuery.findThis 方法
2 - 如果选择器有 :this,则替换为 id 搜索并从 document 进行搜索
3 - 如果选择器不包含:this 进程,通常使用原始find
4 - 使用 $('.target').find('.ancestor:has(:this) .label') 之类的选择器进行测试,以在目标元素的祖先中选择标签
这是基于 cmets 的修订版本,它不会替换现有的 find 并使用生成的唯一 ID。
// Add findThis method to jQuery (with a custom :this check)
jQuery.fn.findThis = function (selector) {
// If we have a :this selector
if (selector.indexOf(':this') > 0) {
var ret = $();
for (var i = 0; i < this.length; i++) {
var el = this[i];
var id = el.id;
// If not id already, put in a temp (unique) id
el.id = 'id'+ new Date().getTime();
var selector2 = selector.replace(':this', '#' + el.id);
ret = ret.add(jQuery(selector2, document));
// restore any original id
el.id = id;
}
ret.selector = selector;
return ret;
}
// do a normal find instead
return this.find(selector);
}
// Test case
$(function () {
$('.starthere').findThis('.level3:has(:this) .label').css({
color: 'red'
});
});
已知问题:
这是基于对 jQuery/Sizzle 源代码的 6 小时奴役,所以要温柔。总是很高兴听到改进这个替换 find 的方法,因为我是 jQuery 内部的新手 :)
然后您可以通过以下方式解决您最初的问题:
<div>
<span data-hide="div:has(:this) span:eq(1)">Span 1</span>
<span>Span 2</span>
</div>
JavaScript:
$('[data-hide]').on('click', function()
{
var selector = $(this).attr('data-hide');
$(this).findThis(selector).hide();
});