jQuery: рефакторинг ленивого кода
Я написал такую функцию, которая включает и выключает элементы:
// category filter
$('.category-filter').click(function() {
var category = $(this).attr('data-category');
$('.category-filter').each(function() {
if ($(this).attr('data-category').indexOf(category) >= 0) {
$(this).removeClass('label-default').addClass('label-success').fadeIn('fast');
$(this).click(function() {
$(this).removeClass('label-success').addClass('label-default').fadeIn('fast');
$('.article_container').each(function() { $(this).fadeIn('fast') })
$('.category-filter').each(function() { $(this).fadeIn('fast') })
})
}
})
$('.article_container').each(function() {
if (!($(this).attr('data-categories').indexOf(category) >= 0)) {
$(this).fadeOut('fast')
}
})
});
Это работает отлично, но мне кажется, что это грязно. На самом деле, у меня есть много функций в моем приложении, которые выглядят похожими. Есть ли руководство по стилю или что-то подобное, чтобы помочь мне рефакторинговать этот код? И вообще, как его преломить?
Я нашел это, но я не уверен, с чего начать.
EDIT
Я сделал jsfiddle, Чтобы проиллюстрировать эту проблему. По существу кнопки должны исключать "статьи", не относящиеся к кнопке. Он должен работать как фильтр. В настоящее время скрипка работает неправильно, потому что я наполовину закончил рефакторинг.
2 ответов:
Трудно понять, что можно упростить, не понимая, что он делает, но я определенно рекомендовал бы сэкономить на селекторах jquery в качестве переменных, чтобы вам не пришлось платить за чтение DOM более одного раза. Людям часто нравится префиксировать такие переменные с помощью
$, чтобы указать, что они являются объектами jquery, но на самом деле это просто предпочтение. Кроме того, никогда не стоит недооценивать важность интервалов.var categoryFilter = $('.category-filter'); var articleContainer = $('.article-container'); categoryFilter.click(function() { var category = $(this).attr('data-category'); categoryFilter.each(function() { if ($(this).attr('data-category').indexOf(category) >= 0) { $(this).removeClass('label-default').addClass('label-success').fadeIn('fast'); $(this).click(function() { $(this).removeClass('label-success').addClass('label-default').fadeIn('fast'); articleContainer.each(function() { $(this).fadeIn('fast') }) categoryFilter.each(function() { $(this).fadeIn('fast') }) }) } }); articleContainer.each(function() { if (!($(this).attr('data-categories').indexOf(category) >= 0)) { $(this).fadeOut('fast') } }) });Правка:
Посмотрев на это немного больше, я вижу пару вещей вы могли бы упростить.
1) как упоминал @dandavis, вы можете создать именованную функцию для ваших вызововfadeIn('fast').2) вы также можете создать именованную функцию с именемfunction fadeFast() { $(this).fadeIn('fast'); }swapClassдля обработки вашихremoveClass().addClass()случаев.function swapClass(context, rm, add) { return context.removeClass(rm).addClass(add); }Затем вызовите его следующим образом:
swapClass($(this), 'label-default', 'label-success').fadeIn('fast');Но на самом деле кажется, что это должно быть в экземпляре jquery (так как вы должны передать это в качестве контекста), что вы можете сделать следующим образом:
$.fn.swapClass = function(oldClass, newClass) { return this.removeClass(oldClass).addClass(newClass); };Затем вызовите его, как это:
$(this).swapClass('label-default', 'label-success').fadeIn('fast');Таким образом, это приводит вас к чему-то вроде:
var categoryFilter = $('.category-filter'); var articleContainer = $('.article-container'); $.fn.swapClass = function(oldClass, newClass) { return this.removeClass(oldClass).addClass(newClass); }; function fadeFast() { $(this).fadeIn('fast'); } categoryFilter.click(function() { var category = $(this).attr('data-category'); categoryFilter.each(function() { var $this = $(this); if ($this.attr('data-category').indexOf(category) >= 0) { $this.swapClass('label-default', 'label-success').fadeIn('fast'); $this.click(function() { $(this).swapClass('label-success', 'label-default').fadeIn('fast'); articleContainer.each(fadeFast); categoryFilter.each(fadeFast); }) } }); articleContainer.each(function() { var $this = $(this); if (!($this.attr('data-categories').indexOf(category) >= 0)) { $this.fadeOut('fast') } }) });
Вот другой способ подхода к вещам, который создает имя класса из атрибута
data-category, чтобы облегчить выбор подобных элементов с помощью простого селектора:$('.category-filter').each(function() { // move data-category attribute to a class name so it's easier to select $(this).addClass("cat_" + $(this).data("category")); }).click(function(e){ var categoryClass = ".cat_" + $(this).data('category'); // now change all items with matching category $(categoryClass).each(function() { $(this).removeClass('label-default').addClass('label-success').fadeIn('fast'); .click(function() { $(this).removeClass('label-success').addClass('label-default'); $('.article_container').fadeIn('fast'); $('.category-filter').fadeIn('fast'); }); }); $('.article_container').not(categoryClass).fadeOut('fast'); });Список изменений:
- скопируйте атрибут data-category в имя класса, чтобы упростить выбор всех соответствующих элементов категории.
- Используйте цепочку в большем количестве мест, чтобы избежать повторного создания объекта jQuery.
- удалите некоторые избыточные вызовы
.fadeIn().- Используйте новое имя класса для затухания правильные статьи
Я думаю, что ваш код имеет проблему с установкой дубликатов обработчиков кликов каждый раз, когда элемент
category-filterнажат. Я не совсем понимаю, почему ты делаешь это таким образом, поэтому я еще не изменил эту часть.
Comments