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');
});
变更列表:
- 将数据类别属性复制到 class 名称,以便 select 所有匹配的类别元素更容易。
- 在更多地方使用链接以避免重复jQuery对象创建。
- 删除一些多余的
.fadeIn()
调用。
- 使用新的 class 名称淡出正确的文章
我认为您的代码在每次单击 category-filter
项目时都安装重复的单击处理程序时存在问题。我不太明白你为什么要这样做,所以我还没有改变那部分。
我写了一个像这样的函数来打开和关闭元素:
// 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');
});
变更列表:
- 将数据类别属性复制到 class 名称,以便 select 所有匹配的类别元素更容易。
- 在更多地方使用链接以避免重复jQuery对象创建。
- 删除一些多余的
.fadeIn()
调用。 - 使用新的 class 名称淡出正确的文章
我认为您的代码在每次单击 category-filter
项目时都安装重复的单击处理程序时存在问题。我不太明白你为什么要这样做,所以我还没有改变那部分。