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
相關文章
相關標籤/搜索