jQuery.stickUp插件重构

  stickUp插件用于实现固定菜单栏效果,原理很简单,说白了就是监听document的scroll事件,滚动到特定值时,将特定元素的position设置为fixed,核心代码如下:

 1  $(document).on(‘scroll‘, function() {
 2                 varscroll = parseInt($(document).scrollTop());
 3                 if (menuSize != null) {
 4                     for (var i = 0; i < menuSize; i++) {
 5                         contentTop[i] = $(‘#‘ + content[i] + ‘‘).offset().top;
 6
 7                         function bottomView(i) {
 8                             contentView = $(‘#‘ + content[i] + ‘‘).height() * .4;
 9                             testView = contentTop[i] - contentView;
10                             //console.log(varscroll);
11                             if (varscroll > testView) {
12                                 $(‘.‘ + itemClass).removeClass(itemHover);
13                                 $(‘.‘ + itemClass + ‘:eq(‘ + i + ‘)‘).addClass(itemHover);
14                             } else if (varscroll < 50) {
15                                 $(‘.‘ + itemClass).removeClass(itemHover);
16                                 $(‘.‘ + itemClass + ‘:eq(0)‘).addClass(itemHover);
17                             }
18                         }
19                         if (scrollDir == ‘down‘ && varscroll > contentTop[i] - 50 && varscroll < contentTop[i] + 50) {
20                             $(‘.‘ + itemClass).removeClass(itemHover);
21                             $(‘.‘ + itemClass + ‘:eq(‘ + i + ‘)‘).addClass(itemHover);
22                         }
23                         if (scrollDir == ‘up‘) {
24                             bottomView(i);
25                         }
26                     }
27                 }
28
29
30
31                 if (vartop < varscroll + topMargin) {
32                     $(‘.stuckMenu‘).addClass(‘isStuck‘);
33                     $(‘.stuckMenu‘).next().closest(‘div‘).css({
34                         ‘margin-top‘: stickyHeight + stickyMarginB + currentMarginT + ‘px‘
35                     }, 10);
36                     $(‘.stuckMenu‘).css("position", "fixed");
37                     $(‘.isStuck‘).css({
38                         top: ‘0px‘
39                     }, 10, function() {
40
41                     });
42                 };
43
44                 if (varscroll + topMargin < vartop) {
45                     $(‘.stuckMenu‘).removeClass(‘isStuck‘);
46                     $(‘.stuckMenu‘).next().closest(‘div‘).css({
47                         ‘margin-top‘: currentMarginT + ‘px‘
48                     }, 10);
49                     $(‘.stuckMenu‘).css("position", "relative");
50                 };
51
52             });

  但是,在实际使用过程中,还是发现诸多不便,

  • 它只支持最后一次调用(因为是使用闭包实现的变量存储,但每次init都基于同样一套变量)
  • 存在一些未经声明的变量调用(即全局变量,这可是很不好的编程习惯啊)
  • 存在一些不必要的函数声明,导致一些不必要的性能损耗(比如上述代码中的bottomView函数)
  • 不支持回调函数,无法支持比较复杂的应用
  • 单页网站时,在页面滚动到parts参数指定的块时,会给对应的菜单块加itemHover类(请参考http://lirancohen.github.io/stickUp/),parts是一个额外指定的参数,而parts中每一个id对应的菜单项又是基于parts参数的顺序的,这是一种不稳定结构(语文老师死得早,凑合着看吧

stickUp原项目在github中很久没有更新了,所以我决定fork出一个分支,然后自己重构stickUp插件,我的项目地址是:https://github.com/VanMess/stickUp,有兴趣的童鞋可以clone下来看看,核心文件的代码只有150多行,结构也比较清晰,大家可以看看,有什么问题请联系我,交流交流。。。。当然,如果哪位大神能提出一些意见就更好了。

新的stickUp代码主要分三个部分:Context类、Context._init_ 初始化函数、Context.onScroll 滚动处理函数。

Context是一个上下文数据结构,用于记录每次调用的上下文信息,这样就解决了上面的第1个问题,代码如下:

 1 var Context = function() {},
 2         _ctxList = {},
 3         lastScrollTop = 0;
 4     Context.prototype = {
 5         dataProperty: ‘data-menu‘,
 6         selector: ‘‘,
 7         itemClass: ‘‘,
 8         itemHover: ‘‘,
 9         jqDom: null,
10         menuItems: [],
11         region: ‘top‘,
12         height: 0,
13         parentMarginTop: 0,
14         top: 0,
15         marginTop: 0,
16         marginBottom: 0,
17         beforeStick: null,
18         afterStick: null,
19         beforeUnstick: null,
20         afterUnstick: null
21 };

  具体每一项的含义、用法,建议大家可以看看源码。

Context._init_ 是一个初始化函数,一个工厂,接受一个option参数,并将之转换为一个Context实例,注意,这里使用了_ctxList 变量来存储历史以来所有的上下文信息,代码如下:

  最后,是Context.prototype.onScroll 类,用于处理页面滚动事件,是整个stickUp的核心所在,代码如下:

onScroll: function(scrollDir, varscroll) {
            var contentView = null,
                testView = null,
                _me = this;

            // 计算并给适当元素添加 itemHover 类
            if ( !! _me.menuItems && _me.menuItems.length > 0) {
                var offset = null,
                    contentTop = 0,
                    tmp_menuTarget = null;
                for (var i = 0; i < _me.menuItems.length; i++) {
                    tmp_menuTarget = $(‘#‘ + $(_me.menuItems[i]).attr(_me.dataProperty));
                    offset = tmp_menuTarget.offset();
                    contentTop = !! offset ? offset.top : 0;

                    // 之前這裡定義了一個bottomView
                    // 会在每次执行这个地方的时候都去创建一个函数
                    // 实际上是很没必要的性能损耗,所以这里将代码移动下面
                    if (scrollDir == ‘down‘ &&
                        varscroll > contentTop - 50 &&
                        varscroll < contentTop + 50) {
                        _me.jqDom.find(‘.‘ + _me.itemClass).removeClass(_me.itemHover);
                        _me.jqDom.find(‘.‘ + _me.itemClass + ‘:eq(‘ + i + ‘)‘).addClass(_me.itemHover);
                    }
                    if (scrollDir == ‘up‘) {
                        // 这里就是原来的bottomView代码
                        contentView = tmp_menuTarget.height() * 0.4;
                        testView = contentTop - contentView;
                        if (varscroll > testView) {
                            _me.jqDom.find(‘.‘ + _me.itemClass).removeClass(_me.itemHover);
                            _me.jqDom.find(‘.‘ + _me.itemClass + ‘:eq(‘ + i + ‘)‘).addClass(_me.itemHover);
                        } else if (varscroll < 50) {
                            _me.jqDom.find(‘.‘ + _me.itemClass).removeClass(_me.itemHover);
                            _me.jqDom.find(‘.‘ + _me.itemClass + ‘:eq(0)‘).addClass(_me.itemHover);
                        }
                    }
                }
            }

            // 固定菜单栏目,使之固定(fixed)
            if (_me.top < varscroll + _me.marginTop) {
                if ( !! _me.beforeStick) _me.beforeStick.call(_me);
                _me.jqDom.addClass(‘isStuck‘);
                if ( !! _me.afterStick) _me.afterStick.call(_me);
                _me.jqDom.next().closest(‘div‘).css({
                    ‘margin-top‘: _me.height + _me.marginBottom + _me.parentMarginTop + ‘px‘
                }, 10);
                _me.jqDom.css("position", "fixed");
                _me.jqDom.css({
                    top: ‘0px‘
                }, 10);
            };

            // 菜單欄目,使之不固定(relative)
            if (varscroll + _me.marginTop < _me.top) {
                if ( !! _me.beforeUnstick) _me.beforeUnstick.call(_me);
                _me.jqDom.removeClass(‘isStuck‘);
                if ( !! _me.afterUnstick) _me.afterUnstick.call(_me);
                _me.jqDom.next().closest(‘div‘).css({
                    ‘margin-top‘: _me.parentMarginTop + ‘px‘
                }, 10);
                _me.jqDom.css("position", "relative");
            };
        }

后记:一直想做一个自己的开源项目,不过还没想清楚要做什么,所以想着先拿别人的来重构、优化,这次使用stickUp是看中它的小(下次想修改百度的ECharts)。stickUp还不是很成熟,但根据我的测试在多个浏览器下都不存在大问题,欢迎大家使用,有什么问题请尽管联系我

另外,看在我辛苦的份上,就麻烦大家留个言鼓励鼓励吧,谢谢
最后附上源码:https://github.com/VanMess/stickUp

jQuery.stickUp插件重构,布布扣,bubuko.com

时间: 2024-10-05 22:29:14

jQuery.stickUp插件重构的相关文章

Jquery Media插件使用,解决在线预览及打开PDF文件

用到过PDF的媛媛and猿猿们,总会发现这大千世界之万能播放器插件,总能少了对媒体控制的接口. 你总会发现PDF无法像img图片一样正常加载展现出来,那么我们在通用语法的基础上拓展出了适用于预览及打开的PDF插件便于开发应用. 最主要的是使用到了一个jquery的插件jquery.media.js,使用这个插件就很容易实现了. 该插件可以播放多种类型的多媒体文件包括:Flash, Quicktime, Windows Media Player, Real Player, MP3, Silverl

jQuery.fly插件实现添加购物车抛物线效果

样例 使用电商 APP 购买商品时,很多都有上图的红色小球抛物线效果,下面通过 jQuery.fly 插件来实现一个简单 Demo. 实现 简单思路: 确定抛物线的起始和终止位置: 通过 js 在起始位置创建一个 document 对象,作为红色小球: 通过 jQuery.fly 插件提供的fly函数来移动小球,移动至终止位置: 当小球到达终止位置后,通过fly插件提供的 onEnd 回调函数,将小球销毁: Demo 源码: <!DOCTYPE html> <html lang=&quo

asp.net 实现在线打印功能,jQuery打印插件PrintArea实现自动分页

使用的组件:jQuery打印插件PrintArea,有兴趣的可以研究一下. 使用方法略过,这里将介绍如何实现打印多页是可以分页. 现在提供两种方法思路: 1.根据特定的打印机型号和使用的纸张类型,然后用JS来算出每页多高,按照每张纸的高度来进行适当的增减高度.(这种方式缺点就是只能针对单中类型的纸张,计算十分的繁琐,要些很多加减法 -_-);). 参考A4纸高度的网页:http://www.jb51.net/office/word/67360.html 2.在如上一个思路的方式,试着查找能不能自

jquery.cookie插件使用

jquery.cookie插件是一个在浏览器端对cookie进行操作的,使用非常方便. jquery.cookie中的操作: jquery.cookie.js插件:百度即可下载 创建一个会话cookie: $.cookie(‘cookieName’,'cookieValue’); 注:当没有指明cookie时间时,所创建的cookie有效期默认到用户浏览器关闭止,故被称为会话cookie. 创建一个持久cookie: $.cookie(‘cookieName’,'cookieValue’,{ex

jQuery验证插件

学习要点: 1.使用 validate.js 插件 2.默认验证规则 3.validate()方法和选项 4.validate.js 其他功能 验证插件(validate.js),是一款验证常规表单数据合法性的插件.使用它,极大的解放了在表单上繁杂的验证过程,并且错误提示显示的完善也增加了用户体验. 一.使用 validate.js 插件 官网下载:http://bassistance.de/jquery-plugins/jquery-plugin-validation最重要的文件是valida

jQuery幻灯片插件Skippr

Skippr是一款带左右箭头,索引按钮,滑动切换效果并且轻量.快速的幻灯片 设置 引入jquery.skippr.css.jquery.js.jquery.skippr.js 注意jQuery必须在jquery.skippr.js之前 <head> <link href="css/jquery.skippr.css" rel="stylesheet" type="text/css" > <script src=&qu

jQuery图片插件自动轮播原理解析

经常看到项目要用到图片轮播效果,一般的操作流程都是先到网上找一个好看的JQuery图片轮播插件,然后看下demo,再配下参数.好了,关机下班回家 其余的就交给插件吧. 是不是感觉有了jQuery,世界变得那么美好呢. 本人最近用的一个插件是 jquery.carousel.js,官方网站是:http://richardscarrott.co.uk/posts/view/jquery-carousel-plugin 下面,我们来讨论一下图片轮播原理. 首先来个简单的demo 效果图如下: 这是个导

jQuery form插件的使用--ajaxForm()和ajaxSubmit()的可选参数项对象

一.前提说明 Form Plugin API 里提供了很多有用的方法可以让你轻松的处理表单里的数据和表单的提交过程. 测试环境:部署到Tomcat中的web项目. 二.简单介绍 本文演示的是:jQuery form插件的使用--ajaxForm()和ajaxSubmit()的可选参数项对象 $('#myForm').ajaxForm(function() { $('#output1').html("提交成功!欢迎下次再来!").show(); }); $('#myForm2').sub

jQuery Validate 插件,表单验证功能

连接地址:http://www.w3cschool.cc/jquery/jquery-plugin-validate.html jQuery Validate jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的验证方法,包括 URL 和电子邮件验证,同时提供了一个用来编写用户自定义方法的 API.所有的捆绑方法默认使用英语作为错误信息,且已翻译成其他 37 种语言. 该插件是由 Jör