使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法


Posted in Javascript onMarch 22, 2016

sticky组件,通常应用于导航条或者工具栏,当网页在某一区域滚动的时候,将导航条或工具栏这类元素固定在页面顶部或底部,方便用户快速进行这类元素提供的操作。

在这篇文章Sticky组件的改进实现提供了一个改进版的sticky组件,并将演示效果应用到了自己的博客。有了类似sticky的这种简单组件,我们就可以在利用它开发更丰富的效果,比如本文要介绍的tab导航和滚动导航。实现简单,演示效果如下:

tab导航(对应tab-sticky.html):

使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法

滚动导航(对应nav-scroll-sticky.html):

使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法

1. tab导航的实现

tab导航的需求是:在点击导航项的时候,除了切换tab内容,还要控制滚动,将要显示的tab内容置顶,并且要刚好显示在sticky元素的下边。由于demo是用bootstrap做的,bootstrap提供的tab组件非常简单好用,我们可以在tab组件提供的shown.bs.tab的事件回调里做滚动控制处理,所以这个效果实现起来比较容易:

<script>
var $target = $('#target');
new Sticky('#sticky', {
unStickyDistance: 60,
target: $target,
wait: 1,
isFixedWidth: false,
getStickyWidth: function($elem) {
return $elem.parent()[0].offsetWidth;
}
});
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
window.scrollTo(0, $target[0].getBoundingClientRect().top + getPageScrollTop() + 1);
});
function getPageScrollTop() {
return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
}
</script>

html结构:

使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法

2. 滚动导航实现

滚动导航相对麻烦一些,tab组件里面,只会显示与当前激活的tab项对应的tab内容,而滚动导航里面,要导航的所有内容都是已经在页面中渲染完毕的,它的需求是:

1)点击导航项的时候,控制页面滚动,自动将与点击的导航项对应的内容置顶显示,并且要刚好显示在sticky元素的下边;

2)页面滚动的时候,根据当前显示的导航内容自动给相应的导航项添加active样式。

尽管听起来复杂,但是demo中的实现还是比较容易:

<script>
var $sticky = $('#sticky');
var $target = $('#target');
new Sticky($sticky, {
unStickyDistance: 60,
target: $target,
wait: 1,
isFixedWidth: false,
getStickyWidth: function ($elem) {
return $elem.parent()[0].offsetWidth;
}
});
var offsetTop = 60;
//实现点击tab项自动滚动到导航内容的效果
$sticky.on('click', 'a', function (e) {
e.preventDefault();
var $this = $(e.currentTarget);
var $parent = $this.parent();
if($parent.hasClass('active')) return;
$sticky.find('li.active').removeClass('active');
$parent.addClass('active');
var target = $this.data('target') || $this.attr('href');
var $target = $(target);
window.scrollTo(0, Math.floor($target[0].getBoundingClientRect().top) + getPageScrollTop() - offsetTop);
});
/**
* Math.floor是解决rect.top或rect.bottom带小数问题
*/
//实现滚动时根据当前显示的导航内容自动给相应的导航项添加active样式
$(window).scroll(throttle(function(){
var $curItem = $sticky.find('a').filter('[href=' + getCurTarget() + ']');
var $parent = $curItem.parent();
if($parent.hasClass('active')) return;
//最后的blur是为了去掉:active及:focus伪类的样式
$sticky.find('li.active').removeClass('active').find('a').trigger('blur');
$parent.addClass('active');
},1));
//获取当前显示的导航内容元素的id
function getCurTarget() {
for(var targets = ['#First', '#Second', '#Third'], i = 0, l = targets.length; i < l; i++) {
var curRect = $(targets[i])[0].getBoundingClientRect();
if(Math.floor(curRect.top) <= offsetTop && Math.floor(curRect.bottom) > offsetTop) {
return targets[i];
}
}
return targets[0];
}
function getPageScrollTop() {
return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
}
//这个函数在实际工作中是应该抽出来的,否则sticky.js里面还有一份重复的
function throttle(func, wait) {
var timer = null;
return function () {
var self = this, args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
return typeof func === 'function' && func.apply(self, args);
}, wait);
}
}
</script>

html结构:

使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法

3. 总结

本文结合sticky组件,提供了2种导航效果实现,兼容IE9+,firefox以及chrome,感兴趣可以下载源码再去详细了解。在实现tab导航的时候,因为有bs的tab组件所以实现起来非常容易,也没有必要把sticky跟tab组件再封装起来形成一个新组件,毕竟效果的实现代码已经比较简单了。在实现滚动导航的时候,因为没有用tab组件,所以滚动导航的那两个需求点都是单独实现的,在实际情况中,这两个功能可以封装成2个独立的组件或者1个组件,这样就能把实现代码写的像tab导航那样简单,不过本文没有再深入去介绍这两个组件的写法,因为这不是本文主要想介绍的内容,虽然我很想这么做,后续肯定会再写博客来介绍这两个组件,简单的东西不造一下轮子,简直是浪费机会。在实现这两个效果的时候,也有2点收获:

1)firefox以及IE,先让网页,然后再刷新,虽然网页还会显示在刷新的位置,但是不会触发scroll事件,所以今后做scroll相关的组件,一定在组件初始化的时候主动掉一次scroll相关的回调;

2)getBoundingClientRect返回的rect对象相关的值,在IE和firefox下,都可能是小数,比如60.2222299999,这样的数,在进行判断的时候可能会跟预期情况不符,导致一些意外的BUG,如果不是特别严谨的话,可以用Math.floor对这些值进行取整,然后再用来计算或者判断。比如滚动导航实现中,rect.top的值60.2222299999,offsetTop的值是60,期望是curRect.top <= offsetTop这个条件能够成立,因为小数的原因,所以它不成立。

Javascript 相关文章推荐
JS删除数组元素的函数介绍
Mar 27 Javascript
js获取php变量的实现代码
Aug 10 Javascript
实测jquery data()如何存值
Aug 18 Javascript
全面兼容的javascript时间格式化函数(比较实用)
May 14 Javascript
jquery实现显示已选用户
Jul 21 Javascript
jQuery实现提交按钮点击后变成正在处理字样并禁止点击的方法
Mar 24 Javascript
详解JavaScript基于面向对象之继承实例
Dec 16 Javascript
JavaScript实现多种排序算法
Feb 24 Javascript
Bootstrap每天必学之滚动监听
Mar 16 Javascript
JS扩展类,克隆对象与混合类实例分析
Nov 26 Javascript
Express使用html模板的详细代码
Sep 18 Javascript
uniapp开发小程序实现滑动页面控制元素的显示和隐藏效果
Dec 10 Javascript
关于JS中match() 和 exec() 返回值和属性的测试
Mar 21 #Javascript
快速掌握Node.js中setTimeout和setInterval的使用方法
Mar 21 #Javascript
快速掌握Node.js事件驱动模型
Mar 21 #Javascript
快速掌握Node.js模块封装及使用
Mar 21 #Javascript
JS DOM实现鼠标滑动图片效果
Sep 17 #Javascript
实践中学习AngularJS表单
Mar 21 #Javascript
javascript单页面手势滑屏切换原理详解
Mar 21 #Javascript
You might like
php利用cookie实现自动登录的方法
2014/12/10 PHP
Symfony2开发之控制器用法实例分析
2016/02/05 PHP
PHP命名空间(namespace)原理与用法详解
2019/12/11 PHP
input+select(multiple) 实现下拉框输入值
2009/05/21 Javascript
js event事件的传递与冒泡处理
2009/12/06 Javascript
HTML长文本截取含有HTML代码同样适用的两种方法
2013/07/31 Javascript
NodeJS的url截取模块url-extract的使用实例
2013/11/18 NodeJs
千分位数字格式化(用逗号隔开 代码已做了修改 支持0-9位逗号隔开)的JS代码
2013/12/05 Javascript
file控件选择上传文件确定后触发的js事件是哪个
2014/03/17 Javascript
用html5 js实现点击一个按钮达到浏览器全屏效果
2014/05/28 Javascript
JavaScript模拟实现继承的方法
2015/03/30 Javascript
详解JavaScript数组和字符串中去除重复值的方法
2016/03/07 Javascript
基于JavaScript FileReader上传图片显示本地链接
2016/05/27 Javascript
JS获取鼠标相对位置的方法
2016/09/20 Javascript
微信JS-SDK选取手机照片上传功能
2017/04/21 Javascript
每个 JavaScript 工程师都应懂的33个概念
2018/10/22 Javascript
element vue validate验证名称重复 输入框与后台重复验证 特殊字符 字符长度 及注意事项小结【实例代码】
2018/11/20 Javascript
javascript实现异形滚动轮播
2019/11/28 Javascript
[02:09]EHOME夺得首届辉夜杯冠军—现场颁奖仪式
2015/12/28 DOTA
[00:12]2018DOTA2亚洲邀请赛 Sccc亮相SOLO赛,今年他又会有什么样的战绩?
2018/04/06 DOTA
Python实现快速多线程ping的方法
2015/07/15 Python
2018年Python值得关注的开源库、工具和开发者(总结篇)
2018/01/04 Python
python os用法总结
2018/06/08 Python
python分布式编程实现过程解析
2019/11/08 Python
Python实现手机号自动判断男女性别(实例解析)
2019/12/22 Python
HTML5中视频音频的使用详解
2017/07/07 HTML / CSS
详解canvas.toDataURL()报错的解决方案全都在这了
2020/03/31 HTML / CSS
精灵市场:Pixie Market
2019/06/18 全球购物
期中考试后的反思
2014/02/08 职场文书
补充协议书范本
2014/04/23 职场文书
致百米运动员广播稿5篇
2014/10/13 职场文书
离婚协议书范文
2015/01/26 职场文书
家庭暴力离婚起诉书
2015/05/18 职场文书
2015年重阳节主持词
2015/07/04 职场文书
2015小学毕业班工作总结
2015/07/21 职场文书
为了顺利买到演唱会的票用Python制作了自动抢票的脚本
2021/10/16 Python