【问题标题】:jQuery: use filter(), but work with both resultsjQuery:使用过滤器(),但同时使用两个结果
【发布时间】:2011-02-17 10:02:52
【问题描述】:

在 jQuery 中,filter() 将您的结果缩减为满足特定条件的那些元素。

这会将列表分成两部分。使用“好的一半”元素很容易:

$("some selector").filter(function() {
  // determine result...
  return result;
}).each( /* do something */ );

但是我如何也可以使用我的“另一半”元素 - 但不做 this 的等价物:

$("some selector").filter(function() {
  // determine result...
  return !result;
}).each( /* do something else */ );

基本上,我想将两个单独的 /* do something */ 部分提供给单个过滤器。一个用于匹配的,另一个用于其他的 - 无需过滤两次。我是否缺少执行此操作的 jQuery 函数?


P.S.:我想我可以做到:

$("some selector").each(function() {
  // determine result...
  if (result)
    /* do something */
  else
    /* do something else */
});

但我希望有更好的东西。

【问题讨论】:

  • 我想它会是each()
  • jsfiddle.net/nZtRF 可能值得注意的一点是,使用not() 方法时,性能会随着元素数量的增加呈指数下降。对于较小的数量,这是微不足道的。对于大批量,您将在过滤器中使用if() 语句获得更好的性能。请参阅上面 jsfiddle 链接上的测试,并弄乱数量。
  • @patrick:非常正确。这是一个严重的缺点。 :-\
  • 标题对我来说看起来很有描述性,标签是它们所属的地方。
  • @Justin Johnson:title 是 Google 将突出显示的内容,而不是标签。我不认为这个编辑是一个实质性的改进,我要把它回滚。此外,这个问题根本不是关于 JavaScript,而是关于 jQuery。请不要仅仅根据纯粹的个人喜好进行编辑而不增加任何重量。

标签: jquery filter


【解决方案1】:

Kobi 推荐的插件形式的方法:

$.fn.invert = function() {
  return this.end().not(this);
};

$('.foo').filter(':visible').hide().invert().show();

注意invert()不会向jQuery栈中添加新元素而是替换最后一个:

$('.foo').filter(':visible').invert().end(); // this will yield $('.foo'), not $('.foo:visible')

编辑:根据 Tomalak 的建议将 prevObject 更改为 end()

【讨论】:

  • 甜蜜。 :-) 我真的很喜欢那个。
  • 我的代码不能被链接,这似乎很好地解决了这个问题。 +1
  • end() 不会比prevObject 更好吗? prevObject 表示我必须在前一步进行过滤,而end() 根据文档指的是“最近的过滤操作”,这意味着它可以退后几步。
  • prevObject 是栈中最后一个 jQuery 对象,是最后一次遍历类型操作的结果。 (其实end()被定义为function() {return this.prevObject || jQuery(null);}。)
  • end() 可能更具前瞻性,因为prevObject 是一个内部功能,而end() 是 API 的一部分。
【解决方案2】:

我不知道这是否更好,但使用 filter() 您可以执行以下操作:

var $others = $();

var $filtered = $('div').filter(function() {
    if(! your filter test) {
        $others.push(this);
    } else {
        return true; 
    }
});

alert($others.length);
alert($filtered.length);

编辑:

起初我尝试从一个空的 jQuery 集 $() 开始,然后使用 add() 用非过滤结果填充它,但无法使其工作。

编辑:

更新为按照 Tomalak 的建议直接在空的 jQuery 对象上使用 push。

【讨论】:

  • 嗯,这是一种方法。不完全顺利,但可行。 :) +1(PS:jQuery是一个数组,你可以直接在上面使用push()
  • 谢谢,是的,如果我知道一种更好的方法来填充过滤器中的others jQuery 集,那就更好了。
  • @Tomalak - 刚刚注意到您关于在 jQuery 对象上直接使用 push() 的评论。有道理,所以我更新了我的答案。谢谢。
  • $() 的小问题 - 它包含文档对象,因此它不是空的。 $(null) 将是一个 really 空白 jQuery 对象。
  • @Tomalak - 它在 1.4 版之前是这样的。来自文档:从 jQuery 1.4 开始,调用不带参数的 jQuery() 方法会返回一个空的 jQuery 集。 不过,上面的 not() 解决方案(和插件版本)看起来很漂亮。
【解决方案3】:
$.fn.if = function(cond, ontrue, onfalse) {
  this.each(function() {
    if (cond.apply(this)) ontrue.apply(this);
    else onfalse.apply(this);
  });
};

$('some selector').if(function() {
  // determine result
}, function() {
  // do something
}, function() {
  // do something else
});

不过,我不确定它是否比手动将 if 放入 each 中更具可读性。

【讨论】:

  • 您必须将索引作为参数添加到cond.apply(),因为 jQuery 本身会将当前索引提供给过滤函数。显然,您必须为 cond, ontrue, onfalse 参数添加类型检查。除此之外,这就是我的想法。一旦你在 jQuery 中链接了 5 个方法,可读性就会受到影响。 ;)
【解决方案4】:

我通常为此使用not - 它可以获取一组元素并将它们从您的选择中删除,留下补码:

var all = $("some selector");
var filtered = all.filter(function() {
  // determine result...
  return result;
});
var others = all.not(filtered);

【讨论】:

  • 不错的一个。我不知道not() 也以这种方式工作。 +1
【解决方案5】:

您可以尝试编写一个 jQuery 插件来执行此操作。查看 filter 函数的代码,并想出一些更精确地满足你想要的东西。可能是这样的:

$("some selector").processList(predicate, successCallback, failureCallback);

然后您将传入三个回调:一个评估对象以查看它是否与过滤器选择匹配(您也可以接受选择器字符串等);一个处理匹配选择​​的对象,另一个处理不匹配的对象。

【讨论】:

  • 是的,这就是我的想法。 :) 不会太复杂,但我不想重新发明轮子。
  • 是的,对不起。我不确定是否存在这样的事情。如果您需要帮助弄清楚如何编写插件,请告诉我们 =)
  • 谢谢。 ^^ 我认为能够做到这一点的插件是显而易见的。我只是想确保我没有遗漏 jQuery 内置的一些聪明的东西。
【解决方案6】:

有趣的问题。我看到你倾向于我的建议:

$("some selector").each(function() { 
  if ($(this).is(SOMEFILTER)) { 
    // do something
  } else {
    // do something  
  }
  // continue with things that apply to everything
}); 

【讨论】:

  • 我希望有一个更 jQuery 风格的方法链解决方案;但从技术上讲,each() 会起作用。 PS:如果过滤结果不能由 jQuery 选择器确定,则不能使用is(),很遗憾。
猜你喜欢
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
  • 2014-10-23
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多