All changes are documented below, however here is a quick-hit list:
- contain everything in $(document).ready() to ensure elements exist before assigning handlers
- make better use of caching,
.find()
, and event delegation
- combine width-specific functions into a single item, with width passed as parameter
- make use of
.on()
rather than shorthand (.click()
, .hover()
) to combine bindings into a single handler
- split
hover
into mouseenter
and mouseleave
to prevent possible double-toggling
Many of these not only make the code more readable, but makes runtime much faster by preventing excessive DOM querying, having smaller object sets to source from, consolidating similarly-applied code, and removal of unneeded code / event handlers.
Here's a draft of the new setup:
/* contain everything within a $(document).ready() function to ensure elements
* exist before handlers assigned to them - shorthand of $(function used here */
$(function() {
/*
* cache objects used more than once, as well as appropriate children
* make use of $(this) rather than re-querying the DOM
* make use of .find() selector when caching children rather than requerying for a new object
*/
var $mainTabs = $(".header-main-tabs"),
$headerDropMenu = $mainTabs.children('.header-drop-menu'),
$navTabsList = $("#nav-tabs-list"),
$searchInputContainer = $("#search-input-container"),
$toggleMobileNav = $("#toggle-mobile-nav");
/* place function declarations prior to event handlers in case any of the handlers use it,
* and consolidate your winWidth-based logic into one function */
function setMobile(winWidth) {
/* this was two separate functions, since you run this every time you can consolidate */
if (winWidth <= 990) {
$navTabsList.hide();
$headerDropMenu.show();
$toggleMobileNav.removeClass("toggle-mobile-nav-clicked");
/* only bind the click handler if winWidth calls for it, and use delegation of click
* events where possible, rather than using CSS selector */
$navTabsList.on('click','li',function() {
$navTabsList.slideUp();
});
} else {
$navTabsList.show();
$headerDropMenu.hide();
$toggleMobileNav.addClass("toggle-mobile-nav-clicked");
/* else remove the binding */
$navTabsList.off('click');
}
}
/* combine multiple on declarations into a single .on() binding */
$mainTabs.on({
click:function(){
$mainTabs.removeClass("header-tab-selected");
$(this).addClass("header-tab-selected");
},
/* separate hover event into mouseenter / mouseleave to prevent possible double-toggling,
* which can happen on rapid hover changes and .toggleClass() */
mouseenter:function(){
$headerDropMenu.addClass("show-drop-menu-hover");
},
mouseleave:function(){
$headerDropMenu.removeClass("show-drop-menu-hover");
}
});
$searchInputContainer.on('click','span',function() {
$(this).toggleClass("fa-times");
$searchInputContainer.fadeToggle("fast");
});
$toggleMobileNav.on('click',function() {
$navTabsList.slideToggle();
$(this).toggleClass("toggle-mobile-nav-clicked");
});
/* call your consolidated function, passing the width as parameter rather then
* assigning to a variable within the function */
setMobile($(window).width());
/* change to non-shorthand in case you wanted to add a different window
* handler later ('load' to wait for images, for example). also, contain it within the
* document.ready so that it doesnt accidentally fire before document.ready (bug in early
* webkit versions) */
$(window).on('resize',function() {
setMobile($(window).width());
});
});
Here it is without the clutter of the comments:
$(function() {
var $mainTabs = $(".header-main-tabs"),
$headerDropMenu = $mainTabs.children('.header-drop-menu'),
$navTabsList = $("#nav-tabs-list"),
$searchInputContainer = $("#search-input-container"),
$toggleMobileNav = $("#toggle-mobile-nav");
function setMobile(winWidth) {
if (winWidth <= 990) {
$navTabsList.hide();
$headerDropMenu.show();
$toggleMobileNav.removeClass("toggle-mobile-nav-clicked");
$navTabsList.on('click','li',function() {
$navTabsList.slideUp();
});
} else {
$navTabsList.show();
$headerDropMenu.hide();
$toggleMobileNav.addClass("toggle-mobile-nav-clicked");
$navTabsList.off('click');
}
}
$mainTabs.on({
click:function(){
$mainTabs.removeClass("header-tab-selected");
$(this).addClass("header-tab-selected");
},
mouseenter:function(){
$headerDropMenu.addClass("show-drop-menu-hover");
},
mouseleave:function(){
$headerDropMenu.removeClass("show-drop-menu-hover");
}
});
$searchInputContainer.on('click','span',function() {
$(this).toggleClass("fa-times");
$searchInputContainer.fadeToggle("fast");
});
$toggleMobileNav.on('click',function() {
$navTabsList.slideToggle();
$(this).toggleClass("toggle-mobile-nav-clicked");
});
setMobile($(window).width());
$(window).on('resize',function() {
setMobile($(window).width());
});
});