Конъюнкция из нескольких 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, время: 05:45. |