用sticky.js实现头部导航栏固定
在页面中,如果页面长度过大,滑动页面时,头部导航栏则会跟着划走。
我的头部导航栏代码为:
1 <div class="headbar"> 2 <center class="headbarTitle">通讯录</center> 3 </div>
固定头部导航栏的方法:引入sticky.js,再加上
1 //头部导航固定 2 $(".headbar").sticky( 3 { 4 topSpacing: 0 5 })
即可。
sticky.js代码如下:
1 (function (factory) { 2 if (typeof define === 'function' && define.amd) { 3 // AMD. Register as an anonymous module. 4 define(['jquery'], factory); 5 } else if (typeof module === 'object' && module.exports) { 6 // Node/CommonJS 7 module.exports = factory(require('jquery')); 8 } else { 9 // Browser globals 10 factory(jQuery); 11 } 12 }(function ($) { 13 var slice = Array.prototype.slice; // save ref to original slice() 14 var splice = Array.prototype.splice; // save ref to original slice() 15 16 var defaults = { 17 topSpacing: 0, 18 bottomSpacing: 0, 19 className: 'is-sticky', 20 wrapperClassName: 'sticky-wrapper', 21 center: false, 22 getWidthFrom: '', 23 widthFromWrapper: true, // works only when .getWidthFrom is empty 24 responsiveWidth: false, 25 zIndex: '100' 26 }, 27 $window = $(window), 28 $document = $(document), 29 sticked = [], 30 windowHeight = $window.height(), 31 scroller = function () { 32 var scrollTop = $window.scrollTop(), 33 documentHeight = $document.height(), 34 dwh = documentHeight - windowHeight, 35 extra = (scrollTop > dwh) ? dwh - scrollTop : 0; 36 37 for (var i = 0, l = sticked.length; i < l; i++) { 38 var s = sticked[i], 39 elementTop = s.stickyWrapper.offset().top, 40 etse = elementTop - s.topSpacing - extra; 41 42 //update height in case of dynamic content 43 s.stickyWrapper.css('height', s.stickyElement.outerHeight()); 44 45 if (scrollTop <= etse) { 46 if (s.currentTop !== null) { 47 s.stickyElement 48 .css({ 49 'width': '', 50 'position': '', 51 'top': '', 52 'z-index': '' 53 }); 54 s.stickyElement.parent().removeClass(s.className); 55 s.stickyElement.trigger('sticky-end', [s]); 56 s.currentTop = null; 57 } 58 } else { 59 var newTop = documentHeight - s.stickyElement.outerHeight() - 60 s.topSpacing - s.bottomSpacing - scrollTop - extra; 61 if (newTop < 0) { 62 newTop = newTop + s.topSpacing; 63 } else { 64 newTop = s.topSpacing; 65 } 66 if (s.currentTop !== newTop) { 67 var newWidth; 68 if (s.getWidthFrom) { 69 padding = s.stickyElement.innerWidth() - s.stickyElement.width(); 70 newWidth = $(s.getWidthFrom).width() - padding || null; 71 } else if (s.widthFromWrapper) { 72 newWidth = s.stickyWrapper.width(); 73 } 74 if (newWidth == null) { 75 newWidth = s.stickyElement.width(); 76 } 77 s.stickyElement 78 .css('width', newWidth) 79 .css('position', 'fixed') 80 .css('top', newTop) 81 .css('z-index', s.zIndex); 82 83 s.stickyElement.parent().addClass(s.className); 84 85 if (s.currentTop === null) { 86 s.stickyElement.trigger('sticky-start', [s]); 87 } else { 88 // sticky is started but it have to be repositioned 89 s.stickyElement.trigger('sticky-update', [s]); 90 } 91 92 if (s.currentTop === s.topSpacing && s.currentTop > newTop || s.currentTop === null && newTop < s.topSpacing) { 93 // just reached bottom || just started to stick but bottom is already reached 94 s.stickyElement.trigger('sticky-bottom-reached', [s]); 95 } else if (s.currentTop !== null && newTop === s.topSpacing && s.currentTop < newTop) { 96 // sticky is started && sticked at topSpacing && overflowing from top just finished 97 s.stickyElement.trigger('sticky-bottom-unreached', [s]); 98 } 99 100 s.currentTop = newTop; 101 } 102 103 // Check if sticky has reached end of container and stop sticking 104 var stickyWrapperContainer = s.stickyWrapper.parent(); 105 var unstick = (s.stickyElement.offset().top + s.stickyElement.outerHeight() >= stickyWrapperContainer.offset().top + 106 stickyWrapperContainer.outerHeight()) && (s.stickyElement.offset().top <= s.topSpacing); 107 108 if (unstick) { 109 s.stickyElement 110 .css('position', 'absolute') 111 .css('top', '') 112 .css('bottom', 0) 113 .css('z-index', ''); 114 } else { 115 s.stickyElement 116 .css('position', 'fixed') 117 .css('top', newTop) 118 .css('bottom', '') 119 .css('z-index', s.zIndex); 120 } 121 } 122 } 123 }, 124 resizer = function () { 125 windowHeight = $window.height(); 126 127 for (var i = 0, l = sticked.length; i < l; i++) { 128 var s = sticked[i]; 129 var newWidth = null; 130 if (s.getWidthFrom) { 131 if (s.responsiveWidth) { 132 newWidth = $(s.getWidthFrom).width(); 133 } 134 } else if (s.widthFromWrapper) { 135 newWidth = s.stickyWrapper.width(); 136 } 137 if (newWidth != null) { 138 s.stickyElement.css('width', newWidth); 139 } 140 } 141 }, 142 methods = { 143 init: function (options) { 144 return this.each(function () { 145 var o = $.extend({}, defaults, options); 146 var stickyElement = $(this); 147 148 var stickyId = stickyElement.attr('id'); 149 var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName; 150 var wrapper = $('<div></div>') 151 .attr('id', wrapperId) 152 .addClass(o.wrapperClassName); 153 154 stickyElement.wrapAll(function () { 155 if ($(this).parent("#" + wrapperId).length == 0) { 156 return wrapper; 157 } 158 }); 159 160 var stickyWrapper = stickyElement.parent(); 161 162 if (o.center) { 163 stickyWrapper.css({ width: stickyElement.outerWidth(), marginLeft: "auto", marginRight: "auto" }); 164 } 165 166 if (stickyElement.css("float") === "right") { 167 stickyElement.css({ "float": "none" }).parent().css({ "float": "right" }); 168 } 169 170 o.stickyElement = stickyElement; 171 o.stickyWrapper = stickyWrapper; 172 o.currentTop = null; 173 174 sticked.push(o); 175 176 methods.setWrapperHeight(this); 177 methods.setupChangeListeners(this); 178 }); 179 }, 180 181 setWrapperHeight: function (stickyElement) { 182 var element = $(stickyElement); 183 var stickyWrapper = element.parent(); 184 if (stickyWrapper) { 185 stickyWrapper.css('height', element.outerHeight()); 186 } 187 }, 188 189 setupChangeListeners: function (stickyElement) { 190 if (window.MutationObserver) { 191 var mutationObserver = new window.MutationObserver(function (mutations) { 192 if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) { 193 methods.setWrapperHeight(stickyElement); 194 } 195 }); 196 mutationObserver.observe(stickyElement, { subtree: true, childList: true }); 197 } else { 198 if (window.addEventListener) { 199 stickyElement.addEventListener('DOMNodeInserted', function () { 200 methods.setWrapperHeight(stickyElement); 201 }, false); 202 stickyElement.addEventListener('DOMNodeRemoved', function () { 203 methods.setWrapperHeight(stickyElement); 204 }, false); 205 } else if (window.attachEvent) { 206 stickyElement.attachEvent('onDOMNodeInserted', function () { 207 methods.setWrapperHeight(stickyElement); 208 }); 209 stickyElement.attachEvent('onDOMNodeRemoved', function () { 210 methods.setWrapperHeight(stickyElement); 211 }); 212 } 213 } 214 }, 215 update: scroller, 216 unstick: function (options) { 217 return this.each(function () { 218 var that = this; 219 var unstickyElement = $(that); 220 221 var removeIdx = -1; 222 var i = sticked.length; 223 while (i-- > 0) { 224 if (sticked[i].stickyElement.get(0) === that) { 225 splice.call(sticked, i, 1); 226 removeIdx = i; 227 } 228 } 229 if (removeIdx !== -1) { 230 unstickyElement.unwrap(); 231 unstickyElement 232 .css({ 233 'width': '', 234 'position': '', 235 'top': '', 236 'float': '', 237 'z-index': '' 238 }); 239 } 240 }); 241 } 242 }; 243 244 // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer): 245 if (window.addEventListener) { 246 window.addEventListener('scroll', scroller, false); 247 window.addEventListener('resize', resizer, false); 248 } else if (window.attachEvent) { 249 window.attachEvent('onscroll', scroller); 250 window.attachEvent('onresize', resizer); 251 } 252 253 $.fn.sticky = function (method) { 254 if (methods[method]) { 255 return methods[method].apply(this, slice.call(arguments, 1)); 256 } else if (typeof method === 'object' || !method) { 257 return methods.init.apply(this, arguments); 258 } else { 259 $.error('Method ' + method + ' does not exist on jQuery.sticky'); 260 } 261 }; 262 263 $.fn.unstick = function (method) { 264 if (methods[method]) { 265 return methods[method].apply(this, slice.call(arguments, 1)); 266 } else if (typeof method === 'object' || !method) { 267 return methods.unstick.apply(this, arguments); 268 } else { 269 $.error('Method ' + method + ' does not exist on jQuery.sticky'); 270 } 271 }; 272 $(function () { 273 setTimeout(scroller, 0); 274 }); 275 }));