patternjavascriptMinor
jQuery Drawer with Tab
Viewed 0 times
withtabdrawerjquery
Problem
I am putting together an animated drawer from scratch for use but also as a learning experience as I am not very strong with jQuery and would really like to get better.
I am hoping that someone here might take a moment to look over my JSFiddle and give me some direction/tips to help me continue to progress?
For example: Is what I put together clean and correct way of doing things? Is creating a function to init the elements for users who have JavaScript as I have done correct? Will what I wrote function well across browsers or are there better ways of achieving this?
jsFiddle
I am hoping that someone here might take a moment to look over my JSFiddle and give me some direction/tips to help me continue to progress?
For example: Is what I put together clean and correct way of doing things? Is creating a function to init the elements for users who have JavaScript as I have done correct? Will what I wrote function well across browsers or are there better ways of achieving this?
jsFiddle
$(document).ready(function() {
//Hide message if user has javascript
function initPage() {
$('#message').css('marginTop', '-60px');
$('#message').find('.droid').css('bottom', '-60px');
}
function slideMessage() {
var message = $('#message');
var tab = $('#tab');
var margin = $('#message').css('marginTop');
var speed = 300;
if (margin != "0px") {
tab.animate({top: "-90px"}, speed);
message.delay(speed).animate({marginTop: "0px"}, speed);
message.find('.droid').delay(1000).animate({bottom: "0px"}, 100);
} else {
message.find('.droid').delay(1000).css({bottom: "-60px"}, 100);
message.animate({marginTop: "-60px"}, speed);
tab.delay(speed).animate({top: "0px"}, speed);
}
}
initPage();
setTimeout(function() {
slideMessage();
}, 1000);
$('#message .close, #tab').click(function() {
slideMessage();
});
});Solution
There are a few issues with your code I've modified it below. Some of the changes I made:
-
cache your jQuery objects
-
reword your
-
parameterize the animations and pull them out into methods of their own
-
move your initialization code so that it is all together
Updated JsFiddle
In response to the comments:
This is very similar to the code you initially put up. I derived it again on a gist using the code you put in your question here (slightly different from the code in the fiddle): https://gist.github.com/3060013/6a4de29001f845c625e2f907752562c7abf9dd85
Clone that repository to see the full history.
-
while your code does work, it has a couple of inefficiencies and the
-
every time you call
-
There is too much extra junk in the way to make it apparent what
-
Caching a jQuery object is an expression for introducing a variable that holds the result of the
-
Perhaps you shouldn't? I'm not 100% on this yet. I think this part of the code can be further cleaned up. I'm still leaning against combining them. I think something that represents this pseudocode would be best, but I'm not sure how to do that best:
That is to say, I don't think the else block should specify the logic of how to do the opposite.
-
cache your jQuery objects
-
reword your
slideMessage condition so that it is more readable-
parameterize the animations and pull them out into methods of their own
-
move your initialization code so that it is all together
Updated JsFiddle
$(function () {
var $message = $('#message'),
$tab = $('#tab');
var speed = 300;
function animateMessage(to) {
// don't want to animate them right now
// rather: animate them when this function I'll return is called
return function () {
return $message.animate({
marginTop: to
}, speed);
};
}
function animateTab(to) {
return function () {
return $tab.animate({
top: to
}, speed);
};
}
//little helper method to queue animations
function queue(immediate) {
var rest = [].splice.call(arguments, 1);
if (immediate) {
$.when(immediate()).then(function () {
queue.apply(window, rest);
});
}
}
function slideMessage() {
var tabVisible = $message.css('marginTop') !== '0px';
if (tabVisible) {
queue(animateTab('-160px'),
animateMessage('0px'));
} else {
queue(animateMessage('-40px'),
animateTab('0px'));
}
}
//Hide message if user has javascript
$message.css('marginTop', '-40px');
slideMessage();
$('#message .close, #tab').click(function() {
slideMessage();
});
});In response to the comments:
This is very similar to the code you initially put up. I derived it again on a gist using the code you put in your question here (slightly different from the code in the fiddle): https://gist.github.com/3060013/6a4de29001f845c625e2f907752562c7abf9dd85
Clone that repository to see the full history.
-
while your code does work, it has a couple of inefficiencies and the
slideMessage has too much going on.-
every time you call
$('...'), jQuery needs to do some work in the background to figure out what you mean in the string. You can instead cache these items and not need to depend on retrieving them repeatedly being fast. In this case it doesn't make much of a difference, but eventually it will cause your page to be slower.-
There is too much extra junk in the way to make it apparent what
slideMessage is doing. A good rule of thumb is to wait a week, then if you cannot glance at a statement and know that it is both in the right place in the function and what it is doing then something is too complex. While your code is probably sensible to you right now I am willing to stake the claim that in a few weeks/months when you go to add some other functionality you would waste some time trying to figure out what this is doing.-
Caching a jQuery object is an expression for introducing a variable that holds the result of the
$('...') function and its related forms.-
Perhaps you shouldn't? I'm not 100% on this yet. I think this part of the code can be further cleaned up. I'm still leaning against combining them. I think something that represents this pseudocode would be best, but I'm not sure how to do that best:
if tabVisible
slide tab out then slide message in
else
do the opposite of what I did to switch them backThat is to say, I don't think the else block should specify the logic of how to do the opposite.
Code Snippets
$(function () {
var $message = $('#message'),
$tab = $('#tab');
var speed = 300;
function animateMessage(to) {
// don't want to animate them right now
// rather: animate them when this function I'll return is called
return function () {
return $message.animate({
marginTop: to
}, speed);
};
}
function animateTab(to) {
return function () {
return $tab.animate({
top: to
}, speed);
};
}
//little helper method to queue animations
function queue(immediate) {
var rest = [].splice.call(arguments, 1);
if (immediate) {
$.when(immediate()).then(function () {
queue.apply(window, rest);
});
}
}
function slideMessage() {
var tabVisible = $message.css('marginTop') !== '0px';
if (tabVisible) {
queue(animateTab('-160px'),
animateMessage('0px'));
} else {
queue(animateMessage('-40px'),
animateTab('0px'));
}
}
//Hide message if user has javascript
$message.css('marginTop', '-40px');
slideMessage();
$('#message .close, #tab').click(function() {
slideMessage();
});
});if tabVisible
slide tab out then slide message in
else
do the opposite of what I did to switch them backContext
StackExchange Code Review Q#13377, answer score: 3
Revisions (0)
No revisions yet.