使用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 操作符整理[推荐收藏]
Nov 15 Javascript
《JavaScript高级编程》学习笔记之object和array引用类型
Nov 01 Javascript
深入探究JavaScript中for循环的效率问题及相关优化
Mar 13 Javascript
BootStrap Table 设置height表头与内容无法对齐的问题
Dec 28 Javascript
bootstrap3 dialog 更强大、更灵活的模态框
Apr 20 Javascript
input框中自动展示当前日期yyyy/mm/dd的实现方法
Jul 06 Javascript
vue 多入口文件搭建 vue多页面搭建的实例讲解
Mar 12 Javascript
浅谈Webpack 持久化缓存实践
Mar 22 Javascript
微信小程序引入VANT组件的方法步骤
Sep 19 Javascript
webpack 处理CSS资源的实现
Sep 27 Javascript
对vuex中store和$store的区别说明
Jul 24 Javascript
使用node-media-server搭建一个简易的流媒体服务器
Jan 20 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
PHP4实际应用经验篇(5)
2006/10/09 PHP
php生成局部唯一识别码LUID的代码
2012/10/06 PHP
Zend Framework教程之连接数据库并执行增删查的方法(附demo源码下载)
2016/03/21 PHP
php自定义函数转换html标签示例
2016/09/29 PHP
JS 树形递归实例代码
2010/05/18 Javascript
Javascript的一种模块模式
2010/09/08 Javascript
基于jQuery判断两个元素是否有重叠部分的代码
2012/07/25 Javascript
利用JS实现浏览器的title闪烁
2013/07/08 Javascript
js键盘事件的keyCode
2014/07/29 Javascript
jquery实现滑动特效代码
2015/08/10 Javascript
jQuery的each循环用法简单示例
2016/06/12 Javascript
jQuery文件上传控件 Uploadify 详解
2016/06/20 Javascript
jQuery使用$获取对象后检查该对象是否存在的实现方法
2016/09/04 Javascript
jquery横向纵向鼠标滚轮全屏切换
2017/02/27 Javascript
React-router中结合webpack实现按需加载实例
2017/05/25 Javascript
浅谈vue实现数据监听的函数 Object.defineProperty
2017/06/08 Javascript
详解webpack的配置文件entry与output
2017/08/21 Javascript
js+html5生成自动排列对话框实例
2017/10/09 Javascript
vue的状态管理模式vuex
2017/11/30 Javascript
JavaScript数据结构与算法之二叉树实现查找最小值、最大值、给定值算法示例
2019/03/01 Javascript
vue 弹窗时 监听手机返回键关闭弹窗功能(页面不跳转)
2019/05/10 Javascript
webpack的 rquire.context用法实现工程自动化的方法
2020/02/07 Javascript
vue通过v-html指令渲染的富文本无法修改样式的解决方案
2020/05/20 Javascript
python实现的各种排序算法代码
2013/03/04 Python
python多线程扫描端口示例
2014/01/16 Python
Python实现提取谷歌音乐搜索结果的方法
2015/07/10 Python
Python实现一个转存纯真IP数据库的脚本分享
2017/05/21 Python
Python 实现中值滤波、均值滤波的方法
2019/01/09 Python
Python通过Manager方式实现多个无关联进程共享数据的实现
2019/11/07 Python
动态设置django的model field的默认值操作步骤
2020/03/30 Python
浅析Python 责任链设计模式
2020/09/11 Python
美国生鲜及杂货电商:FreshDirect
2018/01/29 全球购物
欢迎标语大全
2014/06/21 职场文书
模具设计与制造专业求职信
2014/07/19 职场文书
教师群众路线教育实践活动个人对照检查材料
2014/11/04 职场文书
2015财务年度工作总结范文
2015/05/04 职场文书