• 改良版 导航栏自动跟随


     

    简约版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(),
                    })
                }                    
            })

     

    持续改良中.....

  • 相关阅读:
    外观模式
    虚拟专用网
    DHCP服务
    NFS文件服务器
    samba服务器
    fatal error: Invalid layout of preloaded class
    ftp上传与下载
    byte与char的区别
    android管理联系人操作
    android图像与图像处理系列(一、Bitmap和BitmapFactory)
  • 原文地址:https://www.cnblogs.com/wxyblog/p/12050175.html
Copyright © 2020-2023  润新知