好的,所以我将这个设计用于我正在制作的个人网站的首页:
-------------------------------------------------- -------------------------------------------------- ------------------------------- /
基本上,您点击相应的图标,它会展开以显示信息。很简单。 我经历了另外两个没有成功的设计,但也加入了类似的动画。在每次迭代后修改JS后,我意识到我是: 1)遇到冗余代码 2)开始考虑将来添加更多标签/部分的可能性(我可能需要进行代码扩展)
这导致我开始'发生'我的代码。因此,制作像'handleHorizontalTabs'或'handleVerticalTabs'而不是'handleGamesTab'或'handlePhotographyTab'这样的函数这将避免我为摄影选项卡编写一个全新的功能,这与游戏选项卡只有一个css属性不同。所以我在想,然后我需要传入一个对象而不是一个确切的ID 所以我创建了一些存储所有各自属性的对象文字。创建像这样的中性动画函数(至少在我的情况下)的问题是我 HAVE 来定义可以在函数中使用的每个属性,即使它没有被使用。在滚动到完整代码之前,请考虑以下代码段:
if (active){
// Only animate horizontally
$(elemToAnimate.ID).animate({width: elemToAnimate.ExpandedWidth,
left: elemToAnimate.ExpandedLeft,
right: elemToAnimate.ExpandedRight}, animateDuration)
动画制作时,我可能不需要更改说明,'左'属性。但因为这是一般功能,所以不知道。因此,在我的对象文字中,我仍然需要定义它(它只是原始值)。我注意到了(我把游戏部分保持不变,所以你可以看到这个)如果我只是将它从文字中删除,它会被标记为未定义并且对动画没有影响。我能做到这一点,但我认为这不是好的做法。再加上阅读我的代码的人都会问这个属性在哪里。
我的问题有两个: 在考虑应用的可扩展性时,我应该以编程方式考虑什么? 如何清理/改进此代码?
代码:
https://jsfiddle.net/rc6wnsst/ (PS不是浏览器优化;如果可以,请使用Mozilla)
$(document).ready(function() {
//定义-------------------------------------------- -------------------------------------------------- ---------
//Define object literals
var aboutmeSection = {id: '#aboutme-section', get ID() {return this.id;},
selector: '#person-icon', get Selector() {return this.selector;},
origWidth: $('#aboutme-section').css('width'), get OrigWidth() {return this.origWidth;},
origLeft: $('#aboutme-section').css('left'), get OrigLeft() {return this.origLeft;},
origRight: 'auto', get OrigRight() {return this.origRight;},
origHeight: $('#aboutme-section').css('height'), get OrigHeight() {return this.origHeight;},
origTop: $('#aboutme-section').css('top'), get OrigTop() {return this.origTop;},
origBottom: $('#aboutme-section').css('bottom'), get OrigBottom() {return this.origBottom;},
expandedWidth: '65%', get ExpandedWidth() {return this.expandedWidth;},
expandedLeft: $('#aboutme-section').css('left'), get ExpandedLeft() {return this.expandedLef;},
expandedRight: $('#aboutme-section').css('right'), get ExpandedRight() {return this.expandedRight;},
expandedHeight: '450px', get ExpandedHeight() {return this.expandedHeight;},
expandedTop: '65%', get ExpandedTop() {return this.expandedTop;},
expandedBottom: $('#aboutme-section').css('bottom'), get ExpandedBottom() {return this.expandedBottom;}};
var photographySection = {id: '#photography-tab', get ID() {return this.id;},
selector: '#camera-icon', get Selector() {return this.selector;},
origWidth: $('#photography-tab').css('width'), get OrigWidth() {return this.origWidth;},
origLeft: 'auto', get OrigLeft() {return this.origLeft;},
origRight: $('#photography-tab').css('right'), get OrigRight() {return this.origRight;},
expandedWidth: '40%', get ExpandedWidth() {return this.expandedWidth;},
expandedLeft: 'auto', get ExpandedLeft() {return this.expandedLeft;},
expandedRight: $('#photography-tab').css('right'), get ExpandedRight() {return this.expandedRight;}};
var gamesSection = {id: '#games-tab', get ID() {return this.id;},
selector: '#gamepad-icon', get Selector() {return this.selector;},
origWidth: $('#games-tab').css('width'), get OrigWidth() {return this.origWidth;},
origLeft: $('#games-tab').css('left'), get OrigLeft() {return this.origLeft;},
expandedWidth: '40%', get ExpandedWidth() {return this.expandedWidth;}};
//处理程序-------------------------------------------- -------------------------------------------------- -----------
// Handles aboutme section functionality
function handleAboutMeSection(elemToAnimate, selectedElem, active, animateDuration=500, fadeInDuration=500, fadeOutDuration=250){
// First click
if (active){
// Animate vertically first
$(elemToAnimate.ID).animate({height: elemToAnimate.ExpandedHeight,
top: elemToAnimate.ExpandedTop,
bottom: elemToAnimate.OrigBottom}, animateDuration);
// Animate horizontally second
$(elemToAnimate.ID).animate({width: elemToAnimate.ExpandedWidth,
left: elemToAnimate.ExpandedLeft,
right: elemToAnimate.ExpandedRight}, animateDuration)
// Fade in content and remove active class
$(elemToAnimate.ID).find(".content").fadeIn(fadeInDuration);
$(selectedElem).removeClass('active');
// Second click
} else {
// Fade out content
$(elemToAnimate.ID).find(".content").fadeOut(fadeOutDuration, function(){
// Animate horizontally first
$(elemToAnimate.ID).animate({width: elemToAnimate.OrigWidth,
left: elemToAnimate.OrigLeft,
right: elemToAnimate.OrigRight}, animateDuration);
// Animate vertically second
$(elemToAnimate.ID).animate({height: elemToAnimate.OrigHeight,
top: elemToAnimate.OrigTop,
bottom: elemToAnimate.OrigBottom}, animateDuration)
});
// Add active class back in
$(selectedElem).addClass('active');
}
}
//Handles photography tab functionality
function handleTabs(elemToAnimate, selectedElem, active, animateDuration=500, fadeInDuration=500, fadeOutDuration=250){
// First click
if (active){
// Only animate horizontally
$(elemToAnimate.ID).animate({width: elemToAnimate.ExpandedWidth,
left: elemToAnimate.ExpandedLeft,
right: elemToAnimate.ExpandedRight}, animateDuration)
// Fade in content and remove active class
$(elemToAnimate.ID).find(".content").fadeIn(fadeInDuration);
$(selectedElem).removeClass('active');
// Second click
} else {
// Fade out content and only animate horizontally
$(elemToAnimate.ID).find(".content").fadeOut(fadeOutDuration, function(){
$(elemToAnimate.ID).animate({width: elemToAnimate.OrigWidth,
left: elemToAnimate.OrigLeft,
right: elemToAnimate.OrigRight}, animateDuration);
});
// Add active class back in
$(selectedElem).addClass('active');
}
}
// Main -------------------------------------------- -------------------------------------------------- ----------------
//Hide content initially
$(".content").hide();
//Handle click events
$(".image").click(function() {
//On first click
if ($(this).hasClass("active")) {
switch($(this).attr('id')) {
case 'person-icon':
handleAboutMeSection(aboutmeSection, aboutmeSection.Selector, true);
break;
case 'gamepad-icon':
handleTabs(gamesSection, gamesSection.Selector, true);
break;
case 'camera-icon':
handleTabs(photographySection, photographySection.Selector, true);
break;
default:
break;
}
// On second click
} else {
switch($(this).attr('id')) {
case 'person-icon':
handleAboutMeSection(aboutmeSection, aboutmeSection.Selector, false);
break;
case 'gamepad-icon':
handleTabs(gamesSection, gamesSection.Selector, false);
break;
case 'camera-icon':
handleTabs(photographySection, photographySection.Selector, false);
break;
default:
break;
}
}
});
});
我知道这很多,所以感谢任何愿意帮助的人。
答案 0 :(得分:1)
但是,我想我知道你正在经历的事情,所以让我解决你的问题,只是瞥见代码:
1)在考虑应用的可扩展性时,我应该以编程方式考虑什么?如何清理/改进此代码?
这取决于您打算如何处理它。你需要实现更多的块,也许使用标签和块一起有几个不同的选项?比这更重要的是,你想在几年之后回来并且不要在额头上打自己,然后是的,你可能会稍微重构一下。
在我开始之前,请带上一粒盐。每个程序员都是不同的,所以我的重构示例可能不会与其他人混在一起。如果代码有效,那就是#right#。只有错误的代码是#error#。再次,我的另一种意见。
所以,我要做的是创建一个设置文字对象来处理包含你需要的部分。让我们以我为例。以下是我将如何处理js代码:
// Definitions ----------------------------------------
var section = {
elem: null,
selector: null,
content: null,
opened: false,
origDim: { },
currDim: { },
expdDim: { },
setup: function(settings) { // gets the settings and sets up the initial position
var self = this;
if ( !(
self.is_set(settings) ||
self.is_set(settings.elem) ||
self.is_set(settings.selector) ||
self.is_set(settings.content)
)
)
{
console.log('Your settings must send out an element, a content and a selector');
} else {
self.elem = settings.elem;
self.selector = settings.selector;
self.content = settings.content;
self.origDim = self.getPosition();
}
return self; // this allows chaining
},
// Sets up the range of motion the section will have
setRange: function(expdDim) {
var self = this;
if ( !(self.is_set(expdDim)) ) {
console.log('You have to provide a set of new positions.')
} else {
self.expdDim = {
width: (self.is_set(expdDim.width)?expdDim.width:self.currDim.width),
height: (self.is_set(expdDim.height)?expdDim.height:self.currDim.height),
top: (self.is_set(expdDim.top)?expdDim.top:self.currDim.top),
right: (self.is_set(expdDim.right)?expdDim.right:self.currDim.right),
bottom: (self.is_set(expdDim.bottom)?expdDim.bottom:self.currDim.bottom),
left: (self.is_set(expdDim.left)?expdDim.left:self.currDim.left)
};
}
return self; // this allows chaining
},
// Toggles from opened to close by listening to a property opened
toggle: function(animTime, fadeInTime, fadeOutTime) {
var self = this;
if (self.opened) self.close(animTime, fadeOutTime);
else self.open(self.expdDim, animTime, fadeInTime);
return self; // this allows chaining
},
// Expands the section
open: function(newDim, animTime, fadeInTime) {
var self = this;
if ( !(self.is_set(newDim)) ) console.log('You must send new dimensions!');
else {
var elem = $(self.elem);
elem
.animate(self.optionsVert(newDim), animTime)
.animate(self.optionsHorz(newDim), animTime)
.promise().done( function() {
$(this).find(self.content).fadeIn(fadeInTime)
self.currDim = self.getPosition();
self.opened = true;
});
}
return self; // this allows chaining
},
// Closes the section
close: function(animTime, fadeOutTime) {
var self = this;
var elem = $(self.elem);
// first fade
elem.find(self.content)
.fadeOut(fadeOutTime)
.promise()
.done(function(){
elem
.animate(self.optionsHorz(self.origDim), animTime)
.animate(self.optionsVert(self.origDim), animTime)
.promise()
.done( function() {
self.currDim = self.getPosition();
self.opened = false;
});
});
return self; // this allows chaining
},
// HELPER FUNCTIONS - these do not allow chaining - used as private functions
// Sets up original dimensions based on the element
getPosition: function() {
var self = this;
var offset = $(self.elem).offset();
var posDim = {
width: $(self.elem).width()+'px',
height: $(self.elem).height()+'px',
top: offset.top+'px',
right: parseInt(offset.left)+parseInt($(self.elem).width())+'px',
bottom: parseInt(offset.top)+parseInt($(self.elem).height())+'px',
left: offset.left+'px'
};
return posDim;
},
// validates if a given variable is set
is_set: function(vary) {
return (typeof vary != 'undefined');
},
// returns a subset of dimension variables belonging to the X plane
optionsHorz: function(newDim) {
return {
width: newDim.width,
left: newDim.left,
right: newDim.right
};
},
// returns a subset of dimension variables belonging to the Y plane
optionsVert: function(newDim) {
return {
height: newDim.height,
top: newDim.top,
bottom: newDim.bottom
};
}
};
// Definitions ----------------------------------------
$(document).ready(function() {
// Setting up section about me
var aboutme = section;
aboutme.setup({
elem: '#aboutme-section',
selector: '#person-icon',
content: '.content'
}).setRange({
width: '65%',
height: '450px',
top: '65%'
});
//Hide content initially
$(".content").hide();
//Handle click events
$(".image").click(function() {
switch($(this).attr('id')) {
case 'person-icon':
aboutme.toggle(500,500,250);
break;
default:
break;
}
});
});
这就是你可以模仿你的部分的方法。您可以扩充此块以增强其功能,但是,如果您看一下,设置会变得非常简单。
希望这有帮助。