JQuery: использовать фильтр(), но работать с обоими результатами
В 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 */
});
Но я надеялся на что-то приятнее.
Ответы
Ответ 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')
Изменить: изменено prevObject
на end()
по предложению Tomalak.
Ответ 2
Я обычно использую not
для этого - он может принимать множество элементов и удалять их из вашего выбора, оставляя вас с дополнением
var all = $("some selector");
var filtered = all.filter(function() {
// determine result...
return result;
});
var others = all.not(filtered);
Ответ 3
Вы можете попробовать свои силы при написании плагина jQuery для этого. Проверьте код функции фильтра и придумайте что-то, что более точно, что вы хотите. Это может быть что-то вроде:
$("some selector").processList(predicate, successCallback, failureCallback);
Затем вы передадите три обратных вызова: один, который оценивает объект, чтобы увидеть, соответствует ли он выбранному фильтру (вы также можете принять селекторную строку или тому подобное); тот, который обрабатывает объекты, соответствующие выбранному, и другой, который обрабатывает объекты, которые не совпадают.
Ответ 4
Я не знаю, хорошо ли это, но с помощью filter()
вы можете сделать что-то вроде:
var $others = $();
var $filtered = $('div').filter(function() {
if(! your filter test) {
$others.push(this);
} else {
return true;
}
});
alert($others.length);
alert($filtered.length);
EDIT:
Сначала я попробовал его, начиная с пустого набора jQuery $()
, а затем используя add()
, чтобы заполнить его результатами без фильтра, но не смог заставить его работать.
EDIT:
Обновлено для использования push непосредственно на пустом объекте jQuery, как предлагается Tomalak.
Ответ 5
$.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
});
Я не уверен, что это гораздо более читаемо, чем если бы каждый из них был включен вручную.
Ответ 6
Интересный вопрос. Я вижу, вы склоняетесь к тому, что я собираюсь предложить:
$("some selector").each(function() {
if ($(this).is(SOMEFILTER)) {
// do something
} else {
// do something
}
// continue with things that apply to everything
});