fix-nav.js 3.71 KB
/**
 * make the nav (or any element) to be fixed on top
 * author: Bill.Zhao
 * repository: https://github.com/buildAll/fix-nav.js/blob/master/fix-nav.js
 * license: MIT
 */

let $ = require('yoho-jquery');

(function() {
    $.fn.fixNav = function(options) {

        let defaults = {
            autoRollTop: false, // make the content below the fixed el roll to top when the el is clicked
            zIndex: 999 // the z-index when the element is fixed
        };

        let settings = $.extend({}, defaults, options || {});

        let scrollDirection = {
            direction: '',
            preScrollTop: 0,
            curScrollTop: 0,
            getDirection: function() {
                this.curScrollTop = $(window).scrollTop();
                this.curScrollTop < this.preScrollTop ?
                    this.direction = 'up' :
                    this.direction = 'down';
                this.preScrollTop = this.curScrollTop;
            },
            isUp: function() {
                this.getDirection();
                return this.direction === 'up';
            },
            isDown: function() {
                this.getDirection();
                return this.direction === 'down';
            }
        };

        let utils = {
            lock: false,
            rollTo: function(el, toWhere) {
                $(el).click(function() {
                    if ($(this).css('position') === 'fixed') {
                        utils.lock = true;
                        $('body').animate({
                            scrollTop: toWhere
                        }, 100);
                        setTimeout(function() {
                            utils.lock = false;
                        }, 500);
                    }
                });
            }
        };

        let styleCtrl = {
            isSet: false,
            preStyle: '',
            preTop: null,
            $el: null,
            setFix: function(el, originTop) {
                if (!this.isSet) {
                    this.$el = $(el);

                    this.preStyle = this.$el.attr('style');
                    this.preTop = originTop;

                    utils.lock = true;
                    this.$el.css({
                        position: 'fixed',
                        top: 0,
                        'z-index': settings.zIndex
                    });

                    this.isSet = true;
                    setTimeout(function() {
                        utils.lock = false;
                    }, 500);
                    if (settings.autoRollTop) {
                        utils.rollTo(this.$el.get(0), originTop);
                    }
                }
            },
            clearFix: function() {
                let windowTop;

                if (this.$el) {
                    windowTop = $(window).scrollTop();

                    if (windowTop <= this.preTop) {
                        if (this.preStyle) {
                            this.$el.attr('style', this.preStyle);
                        } else {
                            this.$el.removeAttr('style');
                        }
                        this.isSet = false;
                    }
                }
            }
        };

        return this.each(function(index, el) {
            let originPoistion = $(el).offset().top;

            $(window).scroll(function() {
                if (utils.lock) {
                    return;
                }
                let elementTop = originPoistion - $(window).scrollTop();

                if (scrollDirection.isDown() && elementTop <= 0) {
                    styleCtrl.setFix(el, originPoistion);
                } else {
                    styleCtrl.clearFix();
                }
            });
        });

    };
}());