案例:电梯导航功能
实现功能:
1. 点击左边的小li,会滚动到右边对应的内容区(电梯导航 -> 内容区)
① 当滚动到某一位置时,就让电梯导航显示出来
② 点击电梯导航页面可以滚动到相应内容区域
③ 核心算法:因为电梯导航模块和内容区模块是一一对应的,所以对应的索引号是一样的
④ 当点击电梯导航某个小模块时,就可以拿到当前小模块的索引号
⑤ 就可以把animate要移动的距离求出来:当前索引号内容区模块它的offset().top
⑥ 然后执行动画即可
2. 当滚动到右边的内容区,作边的小li会添加相应的类(内容区 -> 电梯导航)
① 当点击电梯导航的某个小li,当前小li添加current类,兄弟移除类名
② 当页面滚动到内容区域某个模块,左侧电梯导航相对应的小li模块,也会添加current类,兄弟移除current类
③ 触发的事件是页面滚动,因此这个功能要写到页面滚动事件里面
④ 需要用到each遍历内容区域大模块。each里面能拿到内容区域每一个模块元素和索引号
⑤ 判断的条件:被卷去的头部 >= 内容区域里面每个模块的offset().top
⑥ 就利用这个索引号找到相应的电梯导航小li,添加current类
一个bug:当我们刷新页面的时候并不能显示电梯导航,这是因为我们写的代码只允许页面滚动的时候,并且滚动到一定的位置才能显示电梯导航
解决办法:将显示和隐藏电梯导航的功能封装到一个函数里去,在页面加载的时候调用一次,页面滚动的时候再调用一次。
另一个bug:此时如果点击电梯导航的某一个小li时,会出现重新把其他的小li样式背景选择一遍之后才到被点击的小li上。而我们想要的效果是,点击某个小li后,直接去往被点击的小li那添加样式,而不需要它多次选择其他的小li,出现类似抖动的情况。
为什么会出现这个问题呢?这是因为我们的代码中写的是,当我们点击某个小li之后,会使我们的页面滚动起来,而在滚动的过程中,会触发给当前内容区对应的小li增加样式的事件。
如何解决呢?当我们点击了小li,此时不需要执行页面滚动事件里面的小 li 的背景选择。
我们可以使用节流阀的方法,也叫互斥锁,增加一个flag判断条件,判断是点击事件还是滚动事件,如果是点击事件,就上一个锁,不要执行滚动事件里面的代码,点击事件完成之后再释放锁。
<!-- 楼层区 start --> <div class="floor"> <!-- floor不需要给高度,里面的楼层盒子撑开就行了 --> <!-- 一楼家电模块 --> <div class="jiadian w"> 家用电器模块 </div> <!-- 二楼手机模块 --> <div class="shouji w"> 手机通讯模块 </div> <!-- 三楼电脑模块 --> <div class="diannao w"> 电脑办公模块 </div> <!-- 四楼家具模块 --> <div class="jiaju w"> 精品家具模块 <!-- 之后的楼层都接在后面叠加,布局直接采用上面的样式布局,不需要做大的修改 --> </div> <!-- 楼层区 end --> <!-- 固定电梯导航 start --> <div class="fixedtool"> <ul> <li class="current">家用电器</li> <li>手机通讯</li> <li>电脑办公</li> <li>家具家居</li> </ul> </div> <!-- 固定电梯导航 end -->
// JS逻辑代码 $(function() { // 当我们点击了小li,此时不需要执行页面滚动事件里面的小 li 的背景选择。 // 使用节流阀的方法,设置一个flag标识 var flag = true; // 1. 显示隐藏电梯导航 // 直到滚动条滚动到今日推荐的部分,就显示电梯导航 var toolTop = $(".recommend").offset().top; toggleTool(); // 显示和隐藏电梯导航的功能,在页面加载的时候调用一次 function toggleTool() { if ($(document).scrollTop() >= toolTop) { $(".fixedtool").fadeIn(); } else { $(".fixedtool").fadeOut(); } } // 在页面滚动的时候再调用一次 $(window).scroll(function() { toggleTool(); // 3. 页面滚动到某个内容区域,左侧电梯导航小li相应添加和删除current类名 if (flag) { $(".floor .w").each(function(i, ele) { if ($(document).scrollTop() >= $(ele).offset().top) { // console.log(i); i表示当前内容区的索引号 $('.fixedtool li').eq(i).addClass('current').siblings().removeClass('current'); } }); } }); // 2. 点击电梯导航页面可以滚动到相应的内容区域 $('.fixedtool li').click(function() { flag = false; // console.log($(this).index()); // 点击之后让当前的小li添加背景颜色,兄弟元素清除样式 $(this).addClass('current'); $(this).siblings().removeClass('current'); // 当每次点击小li,就需要计算出页面要去往的位置 // 选出对应索引号的内容区的盒子,计算它的.offset().top var current = $(".floor .w").eq($(this).index()).offset().top; // 页面动画滚动效果 $("body, html").stop().animate({ scrollTop: current }, function() { // 当点击小li,执行页面滚动动画完成之后,打开节流阀 flag = true; }); }); })