Конъюнкция из нескольких filter()
Доброго времени суток!
Есть фильтр товаров по разным категориям и сам список товаров. Все данные хранятся в data-аттрибутах. Разметка: <!-- Чекбоксы --> <input type="checkbox" data-type="foo" data-foo="foo_item1"> <input type="checkbox" data-type="foo" data-foo="foo_item2"> ... <input type="checkbox" data-type="bar" data-bar="bar_item1"> <input type="checkbox" data-type="bar" data-bar="bar_item2"> <!-- Товары --> <div class="item" data-foo="foo_item1" data-bar="bar_item1" > <div class="item" data-foo="foo_item2" data-bar="bar_item2" > ... В фильтре две категории: "foo" и "bar". Мне нужно чтобы при выборе чекбоксов из обоих типов подсвечивалось только то, что удовлетворяет двум условиям одновременно. Это было несложно:
function getFilteredItems(type) {
// сомнительный момент – сбор выделенных типов (нужен ли он?)
var checkedTypes = $(':checked').map(function(i,ch){
return $(ch).data(type);
});
// сбор узлов для подсветки
var resultItems = $('.item').filter(function(){
// кэшируем текущий элемент чтобы передать в другой метод
var item = $(this);
// Возвращает true если хотя бы один элемент true
return checkedTypes.some(function(typeItem){
// проверка на совпадение data-аттрибута товара с data-аттрибутом чекбокса
return typeItem==item.data(type);
});
});
return resultItems;
}
$('#filter').find(':checkbox').click(function(){
// кэшируем узлы
var items = $('#goods').find('.item');
var checked = $(':checked');
// убрать подсветку со всех товаров
items.removeClass('highlighted');
// Если отмечен хотя бы один чекбокс – фильтровать
if (checked.length>0) {
items
.css({'opacity':'.3'})
.filter(getFilteredItems('foo'))
.filter(getFilteredItems('bar'))
.addClass('highlighted');
}
else { // иначе – ничего не делать
items.css({'opacity':'1'});
}
});
Всё прекрасно работает, если есть хотя бы один чекбокс в двух категориях одновременно. Но если только в одной, то на выходе из фильтра – 0 элементов. Как сделать так, чтобы при отмеченных чекбоксах только одной категории фильтра отсутствие отмеченных во второй не фильтровало все элементы до нуля? Я пробовал топорно возвращать результаты фильтра в переменные и сделать условия:
var fooItems = items.filter(getFilteredItems('foo'));
var barItems = items.filter(getFilteredItems('bar'));
if (fooItems.length > 0 && barItems.length > 0) {
// фильтр по двум категориям
} else if (fooItems.length > 0) {
// фильтр только по foo
} else if (barItems.length > 0) {
// фильтр только по bar
}
Но на мой взгляд так писать грубо, неправильно и поддерживать это ужасно неудобно (особенно, в случае добавления бОльшего количества категорий). Как мне изменить код? Спасибо! ps: В некоторых случаях (но далеко не всегда) отмечание чекбокса подвешивается где-то на >400 мс. Меня это очень сильно печалит. Если кто-то даст советы по оптимизации данного кода – буду рад критике! |
Цитата:
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<!--
<link rel="stylesheet" type="text/css" href="tmp.css" />
-->
<style type="text/css">
.on {
border: 1px solid;
}
</style>
<script type="text/javascript">
$(document).ready(function (){
$('#case > input:checkbox').click(function (){
$('#items > .item').removeClass('on');
var fltr=filter();
if (fltr=='') return;
$('#items > .item'+fltr).addClass('on');
});
});
function filter() {
var str='';
$('#case > input:checkbox:checked').each(function (){
var typ=$(this).data('type');
str=str+'[data-'+typ+'="'+$(this).data(typ)+'"]'
});
return str;
};
</script>
</head>
<body>
<!-- Чекбоксы -->
<div id='case'>
<input type="checkbox" data-type="foo" data-foo="foo_item1" />
<input type="checkbox" data-type="foo" data-foo="foo_item2" />
...
<input type="checkbox" data-type="bar" data-bar="bar_item1" />
<input type="checkbox" data-type="bar" data-bar="bar_item2" />
</div>
<!-- Товары -->
<div id='items'>
<div class="item" data-foo="foo_item1" data-bar="bar_item1">
foo_item1 bar_item1
</div>
<div class="item" data-foo="foo_item2" data-bar="bar_item2">
foo_item2 bar_item2
</div>
...
</div>
</body>
</html>
|
ksa, спасибо! Согласен – я совсем забыл, что
$(':checked')
дольше, чем даже
$('#filter').find(':checkbox');
или ещё лучше
$('#filter').find('input').filter(':checkbox');
чтобы использовался querySelectorAll(); |
| Часовой пояс GMT +3, время: 21:52. |