jQuery:重构惰性代码

jQuery: refactoring lazy code

我写了一个像这样的函数来打开和关闭元素:

  // 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')
      }
    })
  });

它工作得很好,但对我来说似乎很乱。事实上,我的应用程序中有很多功能看起来很相似。是否有风格指南或类似的东西来帮助我重构这段代码?无论如何应该如何重构?

我找到了 this,但我不确定从哪里开始。

编辑

我做了一个jsfiddle来说明这个问题。本质上,按钮应该消除与按钮无关的 "articles" 。它应该像过滤器一样工作。目前 fiddle 无法正常工作,因为我正在进行重构。

很难知道在不了解它的作用的情况下可以简化什么,但我绝对建议将 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 属性创建 class 名称的事物,以便更容易 select 喜欢带有简单 select 或:

$('.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. 将数据类别属性复制到 class 名称,以便 select 所有匹配的类别元素更容易。
  2. 在更多地方使用链接以避免重复jQuery对象创建。
  3. 删除一些多余的 .fadeIn() 调用。
  4. 使用新的 class 名称淡出正确的文章

我认为您的代码在每次单击 category-filter 项目时都安装重复的单击处理程序时存在问题。我不太明白你为什么要这样做,所以我还没有改变那部分。