В jQuery, filter()
уменьшает Ваш результат до тех элементов, которые выполняют определенное условие.
Это разделяет список в двух частях. Работа с "хорошей половиной" элементов легка:
$("some selector").filter(function() {
// determine result...
return result;
}).each( /* do something */ );
Но как может я работать с "другой половиной" моих элементов, также - но не делая эквивалента этого:
$("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 */
});
Но я надеялся на что-то более хорошее.
Метод, рекомендованный Коби в форме плагина:
$.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')
Изменить: изменил prevObject
на end ()
по предложению Томалака.
Не знаю, лучше ли это, но с помощью 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 ()
заполнить его результатами без фильтрации, но не смог заставить его работать.
РЕДАКТИРОВАТЬ:
Обновлено для использования push непосредственно на пустой объект jQuery, как было предложено Томалаком .
$.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 внутри каждого вручную.
Я обычно использую not
для этого - он может взять массив элементов и удалить их из вашего выбора, оставив вам дополнение:
var all = $("some selector");
var filtered = all.filter(function() {
// determine result...
return result;
});
var others = all.not(filtered);
Вы можете попробовать написать плагин jQuery для этого. Посмотрите код функции filter и придумайте что-то, что делает более точно то, что вы хотите. Это может быть что-то вроде:
$("some selector").processList(predicate, successCallback, failureCallback);
Затем вы передадите три обратных вызова: один, который оценивает объект, чтобы увидеть, соответствует ли он выбору фильтра (вы также можете принять строку селектора, или что-то подобное); один, который обрабатывает объекты, соответствующие выбору, и другой, который обрабатывает объекты, которые не соответствуют.
Интересный вопрос. Я вижу, что вы склоняетесь к тому, что я собирался предложить:
$("some selector").each(function() {
if ($(this).is(SOMEFILTER)) {
// do something
} else {
// do something
}
// continue with things that apply to everything
});