对于一些首页需要展示较多品类的 PC 端商城,靠着主体内容的侧边导航栏是必不可少的。公司官网也用到了这个组件,参考天猫、震坤行、工品汇等网站做了些代码对比解析。

侧边快捷导航栏的定位布局

因为要固定在屏幕的某个位置,所以布局定位第一个想到的是 position:fixed,工品汇和天猫 PC 网站用的就是 fixed 布局。fixed 可以让组件相对于屏幕进行定位,而不是像 absolute 相对于 DOM 文档或者 DOM 中的某一层进行定位。相对来说,可以一步到位。

fixed 相对于屏幕定位,上下距离可以固定,主要遇到的问题是,左右距离不确定。不同的屏幕,可视宽度是不一样的。我在没参考其他网站的情况下想的是通过 @media screen 来动态设置左右间距,导航栏是放在右侧:

    @media screen and (min-width: 1920px) {
        #industry_nav {
            right: 280px;
        }
    }
    @media screen and (max-width: 1600px) {
        #industry_nav {
            right: 0;
        }
    }
    @media screen and (max-width: 1260px) {
        #industry_nav {
            right: -60px;
        }
    }

但这种方法显而易见的过于粗糙了,真正想要的效果是侧边导航栏贴在主题内容旁边。

侧边导航栏紧贴主体内容实现代码:

.nav {
    position: fixed;
    left: 50%
    margin-left: -675px;
}

通过 left: 50% 将导航栏定位在屏幕正中的右侧,然后 margin-left 进行回调,回调距离大于、等于主体内容一半加上导航栏的宽度。上下距离通过 top 或者 bottom 微调,左右可以用 margin-left 微调。

那么使用 absolute 进行侧边导航栏定位是怎么做到上下左右精准定位的呢?查看代码发现,在侧边导航栏外侧,还包了一层,这一层使用了 fixed 定位:

.wrap {
    left: 0;
    top: 0;
    width: 100%;
    position: fixed;
}

父一级绝对定位在屏幕顶部,而导航栏使用 absolute 默认定位的起点就是父一级的左上角位置,因为父级相对于屏幕绝对定位,导航栏间接实现了这一特性。剩下需要做的,就是相对于父级进行微调了:

.nav {
    position: absolute;
    left: 50%;
    margin-left: -625px;
    top: 160px;
}

左右绝对定位还是采用了 left + margin-left 的方式,其他上下通过 top 和 bottom 调整就好。

侧边快捷导航栏的 scroll 选中

天猫、工品汇等网站 js 源码都使用了 webpack 之类的工具打包到一起,没有办法解析。就拿官网的代码做一个 demo 案例:

var industryNav = {
        pos: {},
        get_pos: function() {
            $("body").find(".floor").each(function(index) {
                industryNav.pos[index] = $(this).offset().top;
            });
        },
        style: function(index) {
            var $this = $("#industry_nav").find('.f').eq(index);
            $this.addClass("on").siblings().each(function(){
                $(this).removeClass("on");
            });
        },
        go: function() {
            $("#industry_nav").find('.f').on("click",function(){
                $(window).off("scroll",industryNav.scroll);
                var index = $(this).index();
                $("html,body").animate({scrollTop:industryNav.pos[index]-60},500,function(){
                    industryNav.style(index);
                    $(window).on("scroll",industryNav.scroll);
                });
            });
        },
        scroll: function() {
            var s_top = $(window).scrollTop();
            if( s_top > industryNav.pos[0]-100) {
                $("#industry_nav").show().css({position:'fixed'});
                var n = $("body").find(".floor").length;
                for(var i=0; i<n; i++) {
                    if($("body").find(".floor").eq(i).offset().top-60<=s_top){
                        industryNav.style(i);
                    }
                }
            }else{
                $("#industry_nav").hide().css({position:''});
            }
        },
        init: function() {
            industryNav.get_pos();
            industryNav.go();
            $(window).on("scroll",industryNav.scroll);
        }
    };
    industryNav.init();

代码中将导航栏滑动选中需要用到的几个主要方法写到一个模块里,通过 init() 初始化调用。pos 为模块全局变量,get_pos() 获取到 DOM 文档中所有使用 .floor 类进行标记的楼层,计算他们距离 DOM 顶部的高度,并存储在 pos 中;style() 切换导航栏中按钮的选中状态;go() 绑定导航栏中按钮的点击事件,点击按钮页内跳转到相应的楼层;scroll() 是 window 绑定滑动事件的回调函数,当滑动条滑动时,根据滑动条位置判断是否显示滑动条,确定滑动位置对应导航栏按钮,使用 style() 进行切换按钮选中状态。

.floor 用来标记页面中的楼层,.f 标记与页面楼层对应的导航栏中的按钮。需要一一对应,不然会出现切换错位的情况。

文章目录