zoukankan      html  css  js  c++  java
  • 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             });
    View Code
      但是,在实际使用过程中,还是发现诸多不便,
    • 它只支持最后一次调用(因为是使用闭包实现的变量存储,但每次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 };
    View Code
      具体每一项的含义、用法,建议大家可以看看源码。
        Context._init_ 是一个初始化函数,一个工厂,接受一个option参数,并将之转换为一个Context实例,注意,这里使用了_ctxList 变量来存储历史以来所有的上下文信息,代码如下:
     
    View Code
      最后,是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");
                };
            }
    View Code
    后记:一直想做一个自己的开源项目,不过还没想清楚要做什么,所以想着先拿别人的来重构、优化,这次使用stickUp是看中它的小(下次想修改百度的ECharts)。stickUp还不是很成熟,但根据我的测试在多个浏览器下都不存在大问题,欢迎大家使用,有什么问题请尽管联系我
    另外,看在我辛苦的份上,就麻烦大家留个言鼓励鼓励吧,谢谢
    最后附上源码:https://github.com/VanMess/stickUp
     
     
  • 相关阅读:
    cds.data:=dsp.data赋值有时会出现AV错误剖析
    iOS -- 十进制、十六进制字符串,byte,data等之间的转换
    iOS -- 原生NSStream实现socket
    CA认证原理以及实现(下)
    CA认证原理以及实现(上)
    android -- 存储byte
    iOS -- 字符串(NSString *)转uint8_t的两种方法
    Android -- AsyncTask 使用和缺陷
    Swift oc 混编
    Android -- native关键字
  • 原文地址:https://www.cnblogs.com/vans/p/3789416.html
Copyright © 2011-2022 走看看