这里只是一个初步的解析
stickup.js是一个简单的jQuery插件,源代码只有100多行,它能让页面目标元素 “固定” 在浏览器窗口的顶部,即便页面在滚动,目标元素仍然能出现在设定的位置。
介绍:http://www.bootcss.com/p/stickup/
源码地址:https://github.com/LiranCohen/stickUp
同时,还有一个改进版本可以参考:http://www.cnblogs.com/vans/p/3789416.html
源码地址:https://github.com/VanMess/stickUp
1 jQuery(function($) { 2 3 $(document).ready(function(){ 4 var contentButton = []; 5 var contentTop = []; 6 var content = []; 7 var lastScrollTop = 0; 8 var scrollDir = ''; 9 var itemClass = ''; 10 var itemHover = ''; 11 var menuSize = null; 12 var stickyHeight = 0; 13 var stickyMarginB = 0; 14 var currentMarginT = 0; 15 var topMargin = 0; 16 17 18 $(window).scroll(function(event){ 19 var st = $(this).scrollTop(); 20 if (st > lastScrollTop){ 21 scrollDir = 'down'; 22 } else { 23 scrollDir = 'up'; 24 } 25 lastScrollTop = st; 26 }); 27 28 /***********************************************************/ 29 $.fn.stickUp = function( options ) { 30 // adding a class to users div 31 $(this).addClass('stuckMenu'); 32 //getting options 33 var objn = 0; //objn表示导航条对象有n个 34 if(options != null) { 35 for(var o in options.parts) { //option.parts指导航条对象 36 if (options.parts.hasOwnProperty(o)){ 37 content[objn] = options.parts[objn]; //content对象是options.parts的深拷贝 38 objn++; 39 } 40 } 41 if(objn == 0) { 42 console.log('error:needs arguments'); 43 } 44 45 itemClass = options.itemClass; 46 itemHover = options.itemHover; 47 48 itemTop = options.topLength; //新添加 49 50 if(options.topMargin != null) { 51 if(options.topMargin == 'auto') { 52 topMargin = parseInt($('.stuckMenu').css('margin-top')); 53 } else { 54 //如果以px结尾的topMargin,如options.topMargin:10px,则topMargin=10 此处是否有bug,如 abcpx 55 if(isNaN(options.topMargin) && options.topMargin.search("px") > 0){ 56 topMargin = parseInt(options.topMargin.replace("px","")); 57 //如果topMargin是数字,如options.topMargin:10,则topMargin=10 58 } else if(!isNaN(parseInt(options.topMargin))) { 59 topMargin = parseInt(options.topMargin); 60 } else { 61 //既不是数字,也不是以px结尾,也不是auto,那么就默认为0 62 console.log("incorrect argument, ignored."); 63 topMargin = 0; 64 } 65 } 66 } else { 67 topMargin = 0; 68 } 69 menuSize = $('.'+itemClass).size(); //menuSize指jQuery选择器匹配的元素的数量 70 } 71 stickyHeight = parseInt($(this).height()); 72 stickyMarginB = parseInt($(this).css('margin-bottom')); 73 currentMarginT = parseInt($(this).next().closest('div').css('margin-top')); 74 vartop = parseInt($(this).offset().top); 75 76 varleft = parseInt($(this).offset().left); //新添加 77 varParentWidth = parseInt($(this).parent().offset().width()); //新添加:计算菜单栏悬浮时的宽度 78 varParentLeft = parseInt($(this).parent().offset().left); //新添加:计算菜单栏悬浮时的距离在屏幕左边的宽度 79 80 //$(this).find('*').removeClass(itemHover); 81 } 82 83 //document对象绑定滚动事件,通过监听滚轮位置来识别内容位置,给导航栏切换对应样式 84 $(document).on('scroll', function() { 85 //scrollTop()方法返回或设置匹配元素的滚动条的垂直位置。 86 //如果该方法未设置参数,则返回以像素计的相对滚动条顶部的偏移。 87 varscroll = parseInt($(document).scrollTop()); 88 89 if(menuSize != null){ 90 for(var i=0;i < menuSize;i++) 91 { 92 contentTop[i] = $('#'+content[i]+'').offset().top; //当前内容位置的偏移(第一个元素匹配的偏移坐标) 93 function bottomView(i) { 94 contentView = $('#'+content[i]+'').height()*.4; //当前内容区域高度的 0.4 95 testView = contentTop[i] - contentView; //当前内容区域往上 96 //console.log(varscroll); 97 if(varscroll > testView){ 98 $('.'+itemClass).removeClass(itemHover); 99 $('.'+itemClass+':eq('+i+')').addClass(itemHover); //eq() jQuery遍历方法,下标从0开始 100 } 101 //只距离顶部50px,则默认为导航条的第0个对象 102 else if(varscroll < 50){ 103 $('.'+itemClass).removeClass(itemHover); 104 $('.'+itemClass+':eq(0)').addClass(itemHover); 105 } 106 } 107 108 //滚轮往下走,而且偏移量大于当前内容位置往上50px,且小于往下50px时, 109 //即表示当前内容选中,为当前内容的在导航条上的项目添加active样式 110 if(scrollDir == 'down' && varscroll > contentTop[i]-50 && varscroll < contentTop[i]+50) { 111 $('.'+itemClass).removeClass(itemHover); 112 $('.'+itemClass+':eq('+i+')').addClass(itemHover); 113 } 114 //如果滚轮往上走,则调用上面的函数判断 115 if(scrollDir == 'up') { 116 bottomView(i); 117 } 118 } 119 } 120 121 122 /* 参考示例 123 if(scrollDir == 'up') { 124 for(var i=1;i < menuSize;i++) 125 { 126 //滚轮往上走的时候默认100以内的宽度让上方的项目增加active样式 127 if(varscroll > $('#'+content[i-1]+'').offset().top && varscroll < $('#'+content[i]+'').offset().top-100){ 128 $('.'+itemClass).removeClass(itemHover); 129 $('.'+itemClass+':eq('+(i-1)+')').addClass(itemHover); 130 } 131 } 132 }*/ 133 134 135 136 //两个IF判断滚轮位置是否超过导航条距离屏幕上方高度, 137 //如果超过了,就让导航条浮起来,相反就让导航条回到文档流中 138 if(vartop < varscroll + topMargin){ 139 $('.stuckMenu').addClass('isStuck'); 140 $('.stuckMenu').next().closest('div').css({ 141 'margin-top': stickyHeight + stickyMarginB + currentMarginT + 'px' 142 }, 10); 143 $('.stuckMenu').css("position","fixed"); 144 $('.isStuck').css({ 145 top: '0px' 146 }, 10, function(){ 147 148 }); 149 }; 150 151 if(varscroll + topMargin < vartop){ 152 $('.stuckMenu').removeClass('isStuck'); 153 $('.stuckMenu').next().closest('div').css({ 154 'margin-top': currentMarginT + 'px' 155 }, 10); 156 $('.stuckMenu').css("position","relative"); 157 }; 158 159 }); 160 }); 161 162 });