pagenav.js (5363B)
1 /* 2 * jQuery One Page Nav Plugin 3 * http://github.com/davist11/jQuery-One-Page-Nav 4 * 5 * Copyright (c) 2010 Trevor Davis (http://trevordavis.net) 6 * Dual licensed under the MIT and GPL licenses. 7 * Uses the same license as jQuery, see: 8 * http://jquery.org/license 9 * 10 * @version 3.0.0 11 * 12 * Example usage: 13 * $('#nav').onePageNav({ 14 * currentClass: 'current', 15 * changeHash: false, 16 * scrollSpeed: 750 17 * }); 18 */ 19 20 (function($, window, document, undefined){ 21 22 // our plugin constructor 23 var OnePageNav = function(elem, options){ 24 this.elem = elem; 25 this.$elem = $(elem); 26 this.options = options; 27 this.metadata = this.$elem.data('plugin-options'); 28 this.$win = $(window); 29 this.sections = {}; 30 this.didScroll = false; 31 this.$doc = $(document); 32 this.docHeight = this.$doc.height(); 33 }; 34 35 // the plugin prototype 36 OnePageNav.prototype = { 37 defaults: { 38 navItems: 'a', 39 currentClass: 'current', 40 changeHash: false, 41 easing: 'swing', 42 filter: '', 43 scrollSpeed: 1500, 44 scrollThreshold: 0.5, 45 begin: false, 46 end: false, 47 scrollChange: false 48 }, 49 50 init: function() { 51 // Introduce defaults that can be extended either 52 // globally or using an object literal. 53 this.config = $.extend({}, this.defaults, this.options, this.metadata); 54 55 this.$nav = this.$elem.find(this.config.navItems); 56 57 //Filter any links out of the nav 58 if(this.config.filter !== '') { 59 this.$nav = this.$nav.filter(this.config.filter); 60 } 61 62 //Handle clicks on the nav 63 this.$nav.on('click.onePageNav', $.proxy(this.handleClick, this)); 64 65 //Get the section positions 66 this.getPositions(); 67 68 //Handle scroll changes 69 this.bindInterval(); 70 71 //Update the positions on resize too 72 this.$win.on('resize.onePageNav', $.proxy(this.getPositions, this)); 73 74 return this; 75 }, 76 77 adjustNav: function(self, $parent) { 78 self.$elem.find('.' + self.config.currentClass).removeClass(self.config.currentClass); 79 $parent.addClass(self.config.currentClass); 80 }, 81 82 bindInterval: function() { 83 var self = this; 84 var docHeight; 85 86 self.$win.on('scroll.onePageNav', function() { 87 self.didScroll = true; 88 }); 89 90 self.t = setInterval(function() { 91 docHeight = self.$doc.height(); 92 93 //If it was scrolled 94 if(self.didScroll) { 95 self.didScroll = false; 96 self.scrollChange(); 97 } 98 99 //If the document height changes 100 if(docHeight !== self.docHeight) { 101 self.docHeight = docHeight; 102 self.getPositions(); 103 } 104 }, 250); 105 }, 106 107 getHash: function($link) { 108 return $link.attr('href').split('#')[1]; 109 }, 110 111 getPositions: function() { 112 var self = this; 113 var linkHref; 114 var topPos; 115 var $target; 116 117 self.$nav.each(function() { 118 linkHref = self.getHash($(this)); 119 $target = $('#' + linkHref); 120 121 if($target.length) { 122 topPos = $target.offset().top; 123 self.sections[linkHref] = Math.round(topPos); 124 } 125 }); 126 }, 127 128 getSection: function(windowPos) { 129 var returnValue = null; 130 var windowHeight = Math.round(this.$win.height() * this.config.scrollThreshold); 131 132 for(var section in this.sections) { 133 if((this.sections[section] - windowHeight) < windowPos) { 134 returnValue = section; 135 } 136 } 137 138 return returnValue; 139 }, 140 141 handleClick: function(e) { 142 var self = this; 143 var $link = $(e.currentTarget); 144 var $parent = $link.parent(); 145 var newLoc = '#' + self.getHash($link); 146 147 if(!$parent.hasClass(self.config.currentClass)) { 148 //Start callback 149 if(self.config.begin) { 150 self.config.begin(); 151 } 152 153 //Change the highlighted nav item 154 self.adjustNav(self, $parent); 155 156 //Removing the auto-adjust on scroll 157 self.unbindInterval(); 158 159 //Scroll to the correct position 160 self.scrollTo(newLoc, function() { 161 //Do we need to change the hash? 162 if(self.config.changeHash) { 163 window.location.hash = newLoc; 164 } 165 166 //Add the auto-adjust on scroll back in 167 self.bindInterval(); 168 169 //End callback 170 if(self.config.end) { 171 self.config.end(); 172 } 173 }); 174 } 175 176 e.preventDefault(); 177 }, 178 179 scrollChange: function() { 180 var windowTop = this.$win.scrollTop(); 181 var position = this.getSection(windowTop); 182 var $parent; 183 184 //If the position is set 185 if(position !== null) { 186 $parent = this.$elem.find('a[href$="#' + position + '"]').parent(); 187 188 //If it's not already the current section 189 if(!$parent.hasClass(this.config.currentClass)) { 190 //Change the highlighted nav item 191 this.adjustNav(this, $parent); 192 193 //If there is a scrollChange callback 194 if(this.config.scrollChange) { 195 this.config.scrollChange($parent); 196 } 197 } 198 } 199 }, 200 201 scrollTo: function(target, callback) { 202 var offset = $(target).offset().top-70; 203 204 $('html, body').animate({ 205 scrollTop: offset 206 }, this.config.scrollSpeed, this.config.easing, callback); 207 }, 208 209 unbindInterval: function() { 210 clearInterval(this.t); 211 this.$win.unbind('scroll.onePageNav'); 212 } 213 }; 214 215 OnePageNav.defaults = OnePageNav.prototype.defaults; 216 217 $.fn.onePageNav = function(options) { 218 return this.each(function() { 219 new OnePageNav(this, options).init(); 220 }); 221 }; 222 223 })( jQuery, window , document );