简约版2.0 无横向自动跟随
dom结构为
导航条: .nav-box //样式 : 宽高与.nav 一致, 相对定位 position:relative;
.nav //样式 : display:flex;弹性盒子布局, 对li进行布局 , 设置宽高 ,设置层级z-index:7 避免被其他层级高的元素遮挡
li.active //.active 为选中后的样式
li
li
内容:
.main-cont //每个li对应的内容
.main-cont
.main-cont
js内容
function navFixed(params) {
// 点击导航栏变化颜色
$(params.navParent).on('click', params.nav, function (e) {
//停止监听页面scroll
params.flag = 1;
$(e.target).addClass(params.active).siblings('a').removeClass(params.active);
var nowIndex=$(e.target).index();
$(params.navParent).addClass(params.navActive);
//点击后页面滚动到指定位置
$('html,body').animate({
scrollTop: $(params.itemAll).eq(nowIndex).offset().top - $(params.navParent).outerHeight()
}, 500, function () {
setTimeout(function () {
params.flag = 0;
}, 100)
});
})
//设置简单节流
var timer;
//获取要滚动元素的高度
var arrHeight = [];
$(params.itemAll).each(function (i, v) {
arrHeight.push($(v).offset().top);
})
//获取导航栏父元素相对顶部的高度与scroll比较来判断导航栏是否跟随
var navHeight = $(params.navParent).offset().top;
$(window).scroll(function () {
if (params.flag) {
return;
}
var scrollTop = $(document).scrollTop();
var windowHeight = $(this).height();
var scrollHeight = $(document).height();
//导航栏跟随
if (scrollTop < navHeight) {
$(params.navParent).removeClass('active');
return;
}
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
$(params.navParent).addClass('active');
timer = undefined;
}, 50);
//根据页面高度改变导航栏背景色
arrHeight.forEach(function (v, i) {
if (scrollTop >= v - params.deviation) {
$(params.navParent).find(params.nav).eq(i).addClass(params.active).siblings(params.nav).removeClass(params.active);
}else if(scrollTop + windowHeight == scrollHeight){// 判断滚动到最底部
// alert("已经到最底部了!");
$(".nav-box a:last").addClass('active').siblings().removeClass('active')
}
})
})
}
navFixed({
navParent: '.nav-box',
nav: 'a',
navItem: '.nav-box>a',
navActive:'active',
itemParent: '.main-cont',
itemAll:'.main-cont>div',
active: 'active',
fixedTop: '0',
deviation: $('.nav-main').outerHeight(),
flag: 0
});
导航栏自动跟随部分
css部分:
.container { /*最外层div定宽*/ position: relative; width: 15rem; height: 1rem; margin-top: 20rem; } .con { /*第二层div,设置溢出为滚动条*/ overflow-x: scroll; overflow-y: hidden; height: 1rem; font-size: 0.4rem; width: 15rem; position: absolute; top: 0; } .nav { /*导航条div 设置弹性盒子,使得子集为一行显示,设置子集float也可以 宽度为js动态设置*/ display: flex; } .nav li { /*子集样式*/ width: 4rem; flex: 0 0 4rem; border: 1px solid #000000; } .active { /*选中后的样式*/ background-color: bisque; } /*以下是监听元素的样式*/ .list { margin-bottom: 30rem; } .item { height: 6rem; width: 15rem; border: 1px solid; }
html结构部分:
注意: 导航栏 html结构为三层 , 第一层为给导航栏占位置的, 第二层给导航栏提供 滚动条 , 第三层 是导航子集的容器
<!--导航栏部分--> <div class="container"> <div class="con"> <ul class="nav"> <li class="active"> 1111111</li> <li>222222</li> <li>333333</li> <li>44444</li> <li>55555555</li> <li>66666666</li> <li>7777</li> </ul> </div> </div> <!--监听元素部分--> <div class="list"> <div class="item"> 111111111111111111 </div> <div class="item"> 222222222222222222 </div> <div class="item"> 3333333333333333333 </div> <div class="item"> 444444444444444444 </div> <div class="item"> 5555555555555555555 </div> <div class="item"> 6666666666666666666 </div> <div class="item"> 77777777777777777777 </div> </div>
12月17日js部分
$(function() { scrollgen({ //调用 全部可选参数 导航栏默认为 .nav navChild: '.nav li', //导航栏子集 li navFather: '.con', //导航栏父级 nav: '.nav', //导航栏ul active: '.active', //被选中后的样式 control: '.item', //监听的元素 //isFollow: true //默认为false 为全部显示 false为tab切换 //true 为全部显示, 监视滚动条跟随 }) function scrollgen(obj) { //默认参数 var objDefault = { navChild: $('.nav').children(), //默认获取子节点 navFather: $('.nav').parent(), //默认获取父级 nav: $('.nav'), active: $('.active'), control: $('.nav').parent().parent().next().children(), }; if(!obj) { obj = {} } $.extend(obj, objDefault); var $navChild = $(obj.navChild), $navFather = $(obj.navFather), $nav = $(obj.nav), $active = $(obj.active), active = $active[0].className, $control = $(obj.control), isFollow = obj.isFollow || false; //默认为false $navChild.eq(0).addClass(active).siblings().removeClass(active);//初始值为第一个li选中 $navFather.animate({ scrollLeft: 0 }, 200) var nh = $nav.offset().top, //获取导航栏在文档中的高度 sh = $(document).scrollTop(); //获取滚轮高度 var start_nH = $nav.offset().top index = $navChild.index() + 1 //动态设置nav 宽度 $nav.width(function() { return $navChild.width() * index + 10 + 'px'; }) var Harr = [], //存储item高度容器 Warr = []; //存储nav li offsetleft容器 $control.each(function(index, el) { Harr.push(el.offsetTop); }) $navChild.each((index, el) => { Warr.push(el.offsetLeft); }) if(isFollow == false) { $control.eq(0).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $navChild.click(function() { var i = $(this).index() $control.eq(i).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() - 10 }, 400); $navChild.eq(i).addClass(active).siblings().removeClass(active); var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }, 200) }) } $(window).scroll(function() { sh = $(document).scrollTop(); if($(window).scrollTop() >= nh) { $navFather.css({ 'position': 'fixed', "top": '0' }); Harr.forEach((n, i) => { if($(window).scrollTop() >= n - $nav.height() - 15) { if(isFollow) { $navChild.eq(i).addClass(active).siblings().removeClass(active); } } }); //以下是导航跟随逻辑, //思路:计算出scrollLeft =0 时 元素离文档最左侧的距离 - 滚动后元素离 scrollLeft =0 时 元素离文档最左侧的距离 =滚动距离 var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }) } else { $navFather.css({ 'position': 'absolute', "z-index": '7' }) } }); $navChild.click(function() { var i = $(this).index() var offsetH = $control.eq(i).offset().top; $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() - 10 }, 500) }) } })
12月18日改良后 js部分:
改良后优化:
1.参数可以为 字符串,数组,对象 ,也可以为空 默认参数优化
2.通过 参数 添加tab切换
3.滚动条添加防抖,避免滚动频繁触发函数,造成页面滚动卡顿
4.滚动监听元素位置不准确优化
$(function() { // scrollFollow( // { //调用 全部可选参数 导航栏默认为 .nav // navChild: '.nav li', //导航栏子集 li // navFather: '.con', //导航栏父级 // nav: '.nav', //导航栏ul // active: '.active', //被选中后的样式 // control: '.item', //监听的元素 // //isFollow: true //默认为false false为tab切换 true 为列表全部显示 滚动监听跟随 // } //) scrollFollow(['.nav', '.active', '.item', false]) function scrollFollow(option) { //根据参数的情况,构造出合适的对象,调用 _scrollFollow if(arguments.length === 0) { //没有参数 _scrollFollow({}); } else if(arguments.length === 1) { if(arguments[0] instanceof Array) { //有一个参数 console.log(123) _scrollFollow({ nav: arguments[0][0], active: arguments[0][1], control: arguments[0][2], isFollow: arguments[0][3], }) } else if(arguments[0] instanceof Object) { console.log(456) _scrollFollow(arguments[0]); //第一个参数就是对象 } } else if(arguments.length === 2) { //参数数量大于等于2,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1] }) } else if(arguments.length === 3) { //参数数量大于等于3,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1], control: arguments[2], }) } else if(arguments.length === 4) { //参数数量大于等于4,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1], control: arguments[2], isFollow: arguments[3], }) } } function _scrollFollow(obj) { //默认参数 var objDefault = { navChild: $('.nav').children(), //默认获取子节点 navFather: $('.nav').parent(), //默认获取父级 nav: $('.nav'), active: $('.active'), control: $('.nav').parent().parent().next().children(), }; var obj = Object.assign({}, objDefault, obj); var $navChild = $(obj.navChild), $navFather = $(obj.navFather), $nav = $(obj.nav), $active = $(obj.active), active = $active[0].className, $control = $(obj.control), isFollow = obj.isFollow || false; //默认为false $navChild.eq(0).addClass(active).siblings().removeClass(active); $navFather.animate({ scrollLeft: 0 }, 200) var nh = $nav.offset().top, //获取导航栏在文档中的高度 sh = $(document).scrollTop(); //获取滚轮高度 var start_nH = $nav.offset().top index = $navChild.index() + 1 //动态设置nav 宽度 $nav.width(function() { return $navChild.width() * index + 10 + 'px'; }) var Harr = [], //存储item高度容器 Warr = []; //存储nav li offsetleft容器 $control.each(function(index, el) { Harr.push(el.offsetTop); }) $navChild.each((index, el) => { Warr.push(el.offsetLeft); }) let lock = false; $(window).scroll(function() { _throttle(_scroll, 80); //滚动防抖,防止滚动函数触发频繁,造成滚动卡顿 function _throttle(func, delay = 60) { return(() => { if(lock) { return }; func(); lock = true; setTimeout(() => { lock = false }, delay) })() } function _scroll() { sh = $(document).scrollTop(); if($(window).scrollTop() >= nh) { $navFather.css({ 'position': 'fixed', "top": '0' }); Harr.forEach((n, i) => { if($(window).scrollTop() + $nav.height() >= n - 110) { //tab切换设置 if(isFollow) { $navChild.eq(i).addClass(active).siblings().removeClass(active); } } }); //以下是导航跟随逻辑, //思路:计算出scrollLeft =0 时 元素离文档最左侧的距离 - 滚动后元素离 scrollLeft =0 时 元素离文档最左侧的距离 =滚动距离 var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }) } else { $navFather.css({ 'position': 'absolute', "z-index": '7' }) } } }); if(isFollow == false) { $control.eq(0).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $navChild.click(function() { var i = $(this).index() $control.eq(i).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $navChild.eq(i).addClass(active).siblings().removeClass(active); var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }, 200); $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() - 10 }, 300) }) } else { $navChild.click(function() { var i = $(this).index() //$navChild.eq(i).addClass(active).siblings().removeClass(active); var offsetH = $control.eq(i).offset().top; $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() - 10 }, 300) }) } } })
12月19日 改良后 js部分 ,html部分 , css部分 :
1.参数优化 , 参数数量缩小
2.滚动监听元素位置优化 通过 监听元素距离导航栏距离调整 , 及滚动距离切换active 后续可以扩展为添加参数 调整距离
3.导航栏的辅助父级元素 ,改为动态添加,避免造成影响页面内其nav父级的样式问题
4.导航栏动态添加宽度,改为手动设置宽度, 避免导航栏动态添加的样式将手动设置的样式影响
css部分:
.nav { /*导航条div 设置弹性盒子,使得子集为一行显示,设置子集float也可以 宽度为js动态设置*/ display: flex; width: 100%; } .nav li { /*子集样式*/ width: 4rem; flex: 1; border: 1px solid #000000; height: 1rem; font-size: 0.4rem; width: 50%; } .active { /*选中后的样式*/ background-color: bisque; } /*以下是监听元素的样式*/ .list { margin-bottom: 30rem; } .item { height: 6rem; width: 15rem; border: 1px solid; }
html部分:
<ul class="nav"> <li class="active"> 1111111</li> <li>222222</li> <!--<li>333333</li> <li>44444</li> <li>55555555</li> <li>66666666</li> <li>7777</li>--> </ul> <!--监听元素部分--> <div class="list"> <div class="item"> 111111111111111111 </div> <div class="item"> 222222222222222222 </div> <!--注释测试tab --> <!--<div class="item"> 3333333333333333333 </div> <div class="item"> 444444444444444444 </div> <div class="item"> 5555555555555555555 </div> <div class="item"> 6666666666666666666 </div> <div class="item"> 77777777777777777777 </div>--> </div>
js部分:
$(function() { scrollFollow(['.nav1', '.active', '.item', false]) //参数必填 导航栏类名, 选中类名 , 监听元素类名 , 是否为 非tab function scrollFollow(option) { //根据参数的情况,构造出合适的对象,调用 _scrollFollow if(arguments.length === 0) { //没有参数 _scrollFollow({}); } else if(arguments.length === 1) { if(arguments[0] instanceof Array) { //有一个参数 console.log(123) _scrollFollow({ nav: arguments[0][0], active: arguments[0][1], control: arguments[0][2], isFollow: arguments[0][3], }) } else if(arguments[0] instanceof Object) { console.log(456) _scrollFollow(arguments[0]); //第一个参数就是对象 } } else if(arguments.length === 2) { //参数数量大于等于2,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1] }) } else if(arguments.length === 3) { //参数数量大于等于3,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1], control: arguments[2], }) } else if(arguments.length === 4) { //参数数量大于等于4,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1], control: arguments[2], isFollow: arguments[3], }) } } function _scrollFollow(obj) { //默认参数 var objDefault = { nav: $('.nav'), active: $('.active'), control: $('.nav').parent().parent().next().children(), }; var obj = Object.assign({}, objDefault, obj); var $nav = $(obj.nav), //nav ul $navChild =$nav.children(), //nav子集 li $active = $(obj.active), //选中 active = $active[0].className, //获取选中的class名 $control = $(obj.control), //监听的元素 item isFollow = obj.isFollow || false, //默认为false nav_MarginBottom = 10, //滚动时 nav 距离监听元素的距离 control_top = $control.height() * 0.2; //nav离 滚动距离到下一个元素 还有多远 //当前的$control离nav的距离超过20%,就切换active //动态添加父级 $nav.wrap("<div></div>"); $nav.parent().addClass('navFather'); $('.navFather').css({ 'overflow-x': 'auto', 'overflow-y': 'hidden', 'width': '100%', 'position': 'absolute', 'top': 0, }) $('.navFather').wrap("<div></div>"); $('.navFather').parent().addClass('grandFather'); $('.grandFather').css({ 'position': 'relative', 'height':$('.navFather').height(), }) var $navFather =$('.navFather'); //nav父级 $navChild.eq(0).addClass(active).siblings().removeClass(active);//初始化 $navFather.animate({ scrollLeft: 0 }, 200) var nh = $nav.offset().top, //获取导航栏在文档中的高度 sh = $(document).scrollTop(); //获取滚轮高度 var start_nH = $nav.offset().top index = $navChild.index() + 1 //动态设置nav 宽度 改为 手动添加 // $nav.width(function() { // return $navChild.width() * index +'px'; // }) var Harr = [], //存储item高度容器 Warr = []; //存储nav li offsetleft容器 $control.each(function(index, el) { Harr.push(el.offsetTop); }) // $navChild.each((index, el) => { // Warr.push(el.offsetLeft); // }) let lock = false; //滚动防抖锁 $(window).scroll(function() { function _throttle(func, delay = 60) { return(() => { if(lock) { return }; func(); lock = true; setTimeout(() => { lock = false }, delay) })() } _throttle(_scroll, 80); //滚动防抖,防止滚动函数触发频繁,造成滚动卡顿 function _scroll() { //滚动触发的函数 sh = $(document).scrollTop(); if($(window).scrollTop() >= nh) { $navFather.css({ 'position': 'fixed', "top": '0' }); Harr.forEach((n, i) => { if($(window).scrollTop() + $nav.height() >= n - control_top) { // //tab切换设置 if(isFollow) { $navChild.eq(i).addClass(active).siblings().removeClass(active); } } }); //以下是导航跟随逻辑, //思路:计算出scrollLeft =0 时 元素离文档最左侧的距离 - 滚动后元素离 scrollLeft =0 时 元素离文档最左侧的距离 =滚动距离 var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }) } else { $navFather.css({ 'position': 'absolute', "z-index": '7' }) } } }); if(isFollow == false) { $control.eq(0).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $navChild.click(function() { var i = $(this).index() $control.eq(i).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $navChild.eq(i).addClass(active).siblings().removeClass(active); var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }, 200); $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() }, 300) }) } else { $navChild.click(function() { var i = $(this).index() //点击改变active 改为 滚动监听改变active // $navChild.eq(i).addClass(active).siblings().removeClass(active); var offsetH = $control.eq(i).offset().top; $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() - nav_MarginBottom }, 300) }) } } })
12 28日
JS部分改良:
避免导航栏子集为浮动元素,造成高度坍塌,所以 ,将 js 动态添加上的 navFather 和 grandFather 加上height:100% ,
加上后会造成元素为 navFather 样式为 position :‘fixed‘ 时充满全屏 ,所以加上条件为 $('.navFather').height()
$(function() { scrollFollow(['.nav ul', '.nav .active', '.ui-sortable', false]) //参数必填 导航栏类名, 选中类名 , 监听元素类名 , 是否为 非tab function scrollFollow(option) { //根据参数的情况,构造出合适的对象,调用 _scrollFollow if(arguments.length === 0) { //没有参数 _scrollFollow({}); } else if(arguments.length === 1) { if(arguments[0] instanceof Array) { //有一个参数 console.log(123) _scrollFollow({ nav: arguments[0][0], active: arguments[0][1], control: arguments[0][2], isFollow: arguments[0][3], }) } else if(arguments[0] instanceof Object) { console.log(456) _scrollFollow(arguments[0]); //第一个参数就是对象 } } else if(arguments.length === 2) { //参数数量大于等于2,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1] }) } else if(arguments.length === 3) { //参数数量大于等于3,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1], control: arguments[2], }) } else if(arguments.length === 4) { //参数数量大于等于4,这种情况只需要前两个参数即可 _scrollFollow({ nav: arguments[0], active: arguments[1], control: arguments[2], isFollow: arguments[3], }) } } function _scrollFollow(obj) { //默认参数 var objDefault = { nav: $('.nav'), active: $('.active'), control: $('.nav').parent().parent().next().children(), }; var obj = Object.assign({}, objDefault, obj); var $nav = $(obj.nav), //nav ul $navChild =$nav.children(), //nav子集 li $active = $(obj.active), //选中 active = $active[0].className, //获取选中的class名 $control = $(obj.control), //监听的元素 item isFollow = obj.isFollow || false, //默认为false nav_MarginBottom = 10, //滚动时 nav 距离监听元素的距离 control_top = $control.height() * 0.2; //nav离 滚动距离到下一个元素 还有多远 //当前的$control离nav的距离超过20%,就切换active //动态添加父级
if($nav.parent(). attr("class") != 'navFather') {
$nav.wrap("<div></div>");
$nav.parent().addClass('navFather');
$('.navFather').wrap("<div></div>");
}
$('.navFather').css({
'overflow-x': 'auto',
'overflow-y': 'hidden',
'width': '100%',
'position': 'absolute',
'top': 0,
'height': '100%'
})
if($('.navFather').parent(). attr("class") != 'grandFather') {
$('.navFather').parent().addClass('grandFather');
$('.grandFather').css({
'position': 'relative',
'height': "3.7rem",
})
}
$navChild.eq(0).addClass(active).siblings().removeClass(active);//初始化 $navFather.animate({ scrollLeft: 0 }, 200) var nh = $nav.offset().top, //获取导航栏在文档中的高度 sh = $(document).scrollTop(); //获取滚轮高度 var start_nH = $nav.offset().top index = $navChild.index() + 1 //动态设置nav 宽度 改为 手动添加 // $nav.width(function() { // return $navChild.width() * index +'px'; // }) var Harr = [], //存储item高度容器 Warr = []; //存储nav li offsetleft容器 $control.each(function(index, el) { Harr.push(el.offsetTop); }) // $navChild.each((index, el) => { // Warr.push(el.offsetLeft); // }) let lock = false; //滚动防抖锁 $(window).scroll(function() { function _throttle(func, delay = 60) { return(() => { if(lock) { return }; func(); lock = true; setTimeout(() => { lock = false }, delay) })() } _throttle(_scroll, 80); //滚动防抖,防止滚动函数触发频繁,造成滚动卡顿 function _scroll() { //滚动触发的函数 sh = $(document).scrollTop(); if($(window).scrollTop() >= nh) { $navFather.css({ 'position': 'fixed', "top": '0', 'height': $('.navFather').height(), }); Harr.forEach((n, i) => { if($(window).scrollTop() + $nav.height() >= n - control_top) { // //tab切换设置 if(isFollow) { $navChild.eq(i).addClass(active).siblings().removeClass(active); } } }); //以下是导航跟随逻辑, //思路:计算出scrollLeft =0 时 元素离文档最左侧的距离 - 滚动后元素离 scrollLeft =0 时 元素离文档最左侧的距离 =滚动距离 var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }) } else { $navFather.css({ 'position': 'absolute', "z-index": '7' }) } } }); if(isFollow == false) { $control.eq(0).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $navChild.click(function() { let i = $(this).index() $control.eq(i).css({ 'display': 'block' }).siblings().css({ 'display': 'none' }); $navChild.eq(i).addClass(active).siblings().removeClass(active); var item = $("." + active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + $navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft var centerLeft = ($navFather.width() - item.width()) / 2; $navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }, 200); $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() }, 300) }) } else { $navChild.click(function() { var i = $(this).index() //点击改变active 改为 滚动监听改变active // $navChild.eq(i).addClass(active).siblings().removeClass(active); var offsetH = $control.eq(i).offset().top; $('html,body').animate({ scrollTop: $control.eq(i).offset().top - $nav.height() - nav_MarginBottom }, 300) }) } } })
3月25日改良 ,
1.功能模块化,逻辑处理简单化,避免代码沉余。
2.减少因动态增加dom带来的性能和布局问题
let obj={ el:".warp", //根元素 //初始化 init(options){ //初始化数据 this.handleGetData(options); //初始化子集active this.$navChild.eq(0).addClass(this.active).siblings().removeClass(this.active); //初始化 样式 this.$navFather.css({ 'overflow-x': 'auto', 'overflow-y': 'hidden', 'position': 'relative', 'top': 0, }) //初始化滚动条 this.$navFather.animate({ scrollLeft: 0 }, 200); this.nh=this.$nav.offset().top; //获取导航栏在文档中的高度 //执行函数 this._scrollFollow(); }, //tab切换函数 handleTba(){ }, //跟随滚动函数 _scrollFollow(){ let _this=this; _this.getHeight() ; _this._handleScroll(); _this.handleClick(); }, //获取滚动条高度和被监听元素的offset数组 getHeight(){ let _this=this; //动态设置nav 宽度 改为 手动添加 _this.Harr = []; //存储item高度容器 _this.$control.each(function(index,el) { _this.Harr.push(el.offsetTop); }); console.log(_this.Harr) }, //防抖函数 _handleThrottle(fnc,delay = 60) { const _this=this; return(() => { if(_this.lock) { return }; _this.handleIfScrollTop(); _this.lock = true; setTimeout(() => { _this.lock = false }, delay) })() }, //滚动触发的函数 _handleScroll(){ let _this=this; _this.lock = false; //滚动防抖锁 $(window).scroll(function() { _this._handleThrottle(_this.handles,50); //滚动防抖,防止滚动函数触发频繁,造成滚动卡顿 }); }, //判断是否超过导航栏 handleIfScrollTop(){ let _this=this; if($(window).scrollTop() >= _this.nh) { _this.$navFather.css({ 'position': 'fixed', "top": '0', "z-index": '7', 'height': _this.$nav.height(), }); _this.Harr.forEach((n, i) => { if($(window).scrollTop() + _this.$nav.height() >= n - _this.control_top) { // //active切换设置 _this.$navChild.eq(i).addClass(_this.active).siblings().removeClass(_this.active); } }); } else { _this.$navFather.css({ 'position': 'relative', "z-index": '7' }) } _this.handleLeft(); //动态active居中 }, // 点击导航条触发函数 handleClick(){ let _this=this; this.$navChild.click(function() { var i = $(this).index() //点击改变active 改为 滚动监听改变active var offsetH = _this.$control.eq(i).offset().top; $('html,body').animate({ scrollTop: _this.$control.eq(i).offset().top - _this.$nav.height() - _this.nav_MarginBottom }, 300); }) }, //计算选择active的位置,active动态跟随 handleLeft(){ //以下是导航跟随逻辑, //思路:计算出scrollLeft =0 时 元素离文档最左侧的距离 - 滚动后元素离 scrollLeft =0 时 元素离文档最左侧的距离 =滚动距离 var item = $(".nav_box ." + this.active); var itemOffset = item.offset(); //元素离 scrollLeft等于0 时的距离 var itemOffsetLeft = itemOffset.left + this.$navFather.scrollLeft(); //scrollLeft等于0,居中时的offsetLeft距离 var centerLeft = (this.$nav.width() - item.width()) / 2; this.$navFather.stop().animate({ scrollLeft: itemOffsetLeft - centerLeft }) }, //处理传入参数 handleGetData(option) { //根据参数的情况,构造出合适的对象,调用 _scrollFollow if(arguments.length === 0) { //没有参数 this.obj={}; } else if(arguments.length === 1) { if(arguments[0] instanceof Array) { //有一个参数 this.obj={ nav: arguments[0][0], active: arguments[0][1], control: arguments[0][2], isFollow: arguments[0][3], } } else if(arguments[0] instanceof Object) { console.log(456) this.obj=arguments[0]; //第一个参数就是对象 } } else if(arguments.length === 2) { //参数数量大于等于2,这种情况只需要前两个参数即可 this.obj={ nav: arguments[0], active: arguments[1] } } else if(arguments.length === 3) { //参数数量大于等于3,这种情况只需要前两个参数即可 this.obj={ nav: arguments[0], active: arguments[1], control: arguments[2], } } else if(arguments.length === 4) { //参数数量大于等于4,这种情况只需要前两个参数即可 this.obj={ nav: arguments[0], active: arguments[1], control: arguments[2], isFollow: arguments[3], } } //默认参数 this.objDefault = { nav: $('.nav'), active: $('.active'), control: $('.nav').parent().parent().next().children(), isTab:false }; this.data = Object.assign({}, this.objDefault, this.obj); this.$nav = $(this.data.nav); //nav ul this.$navChild =this.$nav.children(); //nav子集 li this.$active = $(this.data.active); //选中 this.active =this.$active[0].className; //获取选中的class名 this.$control = $(this.data.control); //监听的元素 item this.isFollow = this.data.isFollow || false; //默认为false this.nav_MarginBottom = 10, //滚动时 nav 距离监听元素的距离 this.control_top = this.$control.height() * 0.2; //nav离 滚动距离到下一个元素 还有多远 //当前的$control离nav的距离超过20%,就切换active this.$navFather =this.$nav.parent(); //nav父级 } }
obj.init(['.nav_box ul', '.nav_box .active', '.con']) //active的父级 , active选中项,被监听滚动的元素
6月24日 简约版 无横向自动跟随
//初始化样式,避免编辑模式影响 $('.nav').css({ 'position': 'relative', 'top': 0, 'height': $('.nav').parent().height(), }) $('.nav li').eq(0).addClass('active').siblings().removeClass('active') var Harr = []; $('.commodity_title_box').each(function(i,list){ Harr.push($(this).offset().top) }) $('.nav li').click(function(e){ e.preventDefault() var i = $(this).index(); $('html,body').stop().animate({ scrollTop:Harr[i]-$(this).height()-10 },200) }) $(window).scroll(function() { if($(window).scrollTop() >= $('.nav').parent().offset().top) { $('.nav').css({ 'position': 'fixed', 'top': 0, 'height': $('.nav').parent().height(), 'z-index':'7' }); Harr.forEach(function(H,i){ if(Harr[i]-$('.nav').height()-280<$(window).scrollTop()){ $('.nav li').eq(i).addClass('active').siblings().removeClass('active') } }) } else { $('.nav').css({ 'position': 'relative', 'top': 0, 'height': $('.nav').parent().height(), }) } })