PC 端侧边快捷导航栏的实现原理解析
对于一些首页需要展示较多品类的 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
标记与页面楼层对应的导航栏中的按钮。需要一一对应,不然会出现切换错位的情况。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。