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, Чтобы проиллюстрировать эту проблему. По существу кнопки должны исключать "статьи", не относящиеся к кнопке. Он должен работать как фильтр. В настоящее время скрипка работает неправильно, потому что я наполовину закончил рефакторинг.

612   2  

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').
function fadeFast() {
  $(this).fadeIn('fast');
}
2) вы также можете создать именованную функцию с именем 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');
});

Список изменений:

  1. скопируйте атрибут data-category в имя класса, чтобы упростить выбор всех соответствующих элементов категории.
  2. Используйте цепочку в большем количестве мест, чтобы избежать повторного создания объекта jQuery.
  3. удалите некоторые избыточные вызовы .fadeIn().
  4. Используйте новое имя класса для затухания правильные статьи

Я думаю, что ваш код имеет проблему с установкой дубликатов обработчиков кликов каждый раз, когда элемент category-filter нажат. Я не совсем понимаю, почему ты делаешь это таким образом, поэтому я еще не изменил эту часть.

Comments

    Ничего не найдено.