如何以均匀的速度保持Skrollr-Menu?

时间:2015-05-16 19:30:17

标签: javascript jquery skrollr

我正在使用Skrollr菜单使用以下

按下按钮上的页面

HTML

<a href="#End"><div class="trigger-scroll left">&gt;</div></a>
... the page i want to reveal, using scrolling ...
<section id="End" class="scroll-here">
    <div class="hsContainer bottom"></div>
</section>

的JavaScript

var s = skrollr.init();

skrollr.menu.init(s, {
    animate: true,
    //How long the animation should take in ms.
    duration: function(currentTop, targetTop) {
        //By default, the duration is hardcoded at 500ms.
        return 18000;

        //But you could calculate a value based on the current scroll position (`currentTop`) and the target scroll position (`targetTop`).
        //return Math.abs(currentTop - targetTop) * 10;
    },

    //This event is triggered right before we jump/animate to a new hash.
    change: function(newHash, newTopPosition) {
        //Do stuff
    },

    //Add hash link (e.g. `#foo`) to URL or not.
    updateUrl: false //defaults to `true`.
});

当我点击按钮时会发生什么,它可以正常工作,这不是问题。

问题在于它似乎改变了速度,因为skrollr-menu为页面设置了动画。它开始很快,这意味着页面上的前几个元素(大约是第一个2000px)闪过不可读。然后速度均匀,直到最后3000px(大约),其中skrollr菜单非常慢。我想要的是单击按钮类似于按住键盘或滚动侧边栏上的向下箭头,默认情况下skrollr菜单似乎没有。

我尝试使用数学公式来改变速度,但无论我尝试什么,问题仍然存在,而且似乎没有任何“简单”方式来改变加速度,我怀疑问题出在某处在Skrollr.menu.js文件中,但我看不到哪里。

有什么方法可以使滚动速度均匀,而不是在开始时快速而在结束时减慢?

注意:我在JavaScript或jQuery方面不是很有经验,所以它可能是我忽略的一些简单。

github上的skrollr菜单 https://github.com/Prinzhorn/skrollr-menu

Skrollr.menu.js

 /*!
 * Plugin for skrollr.
 * This plugin makes hashlinks scroll nicely to their target position.
 *
 * Alexander Prinzhorn - https://github.com/Prinzhorn/skrollr
 *
 * Free to use under terms of MIT license
 */
(function(document, window) {
    'use strict';

    var DEFAULT_DURATION = 500;
    var DEFAULT_EASING = 'sqrt';
    var DEFAULT_SCALE = 1;

    var MENU_TOP_ATTR = 'data-menu-top';
    var MENU_OFFSET_ATTR = 'data-menu-offset';
    var MENU_DURATION_ATTR = 'data-menu-duration';
    var MENU_IGNORE_ATTR = 'data-menu-ignore';

    var skrollr = window.skrollr;
    var history = window.history;
    var supportsHistory = !!history.pushState;

    /*
        Since we are using event bubbling, the element that has been clicked
        might not acutally be the link but a child.
    */
    var findParentLink = function(element) {
        //We reached the top, no link found.
        if(element === document) {
            return false;
        }

        //Yay, it's a link!
        if(element.tagName.toUpperCase() === 'A') {
            return element;
        }

        //Maybe the parent is a link.
        return findParentLink(element.parentNode);
    };

    /*
        Handle the click event on the document.
    */
    var handleClick = function(e) {
        //Only handle left click.
        if(e.which !== 1 && e.button !== 0) {
            return;
        }

        var link = findParentLink(e.target);

        //The click did not happen inside a link.
        if(!link) {
            return;
        }

        if(handleLink(link)) {
            e.preventDefault();
        }
    };

    /*
        Handles the click on a link. May be called without an actual click event.
        When the fake flag is set, the link won't change the url and the position won't be animated.
    */
    var handleLink = function(link, fake) {
        var hash;

        //When complexLinks is enabled, we also accept links which do not just contain a simple hash.
        if(_complexLinks) {
            //The link points to something completely different.
            if(link.hostname !== window.location.hostname) {
                return false;
            }

            //The link does not link to the same page/path.
            if(link.pathname !== document.location.pathname) {
                return false;
            }

            hash = link.hash;
        } else {
            //Don't use the href property (link.href) because it contains the absolute url.
            hash = link.getAttribute('href');
        }

        //Not a hash link.
        if(!/^#/.test(hash)) {
            return false;
        }

        //The link has the ignore attribute.
        if(!fake && link.getAttribute(MENU_IGNORE_ATTR) !== null) {
            return false;
        }

        //Now get the targetTop to scroll to.
        var targetTop;

        var menuTop;

        //If there's a handleLink function, it overrides the actual anchor offset.
        if(_handleLink) {
            menuTop = _handleLink(link);
        }
        //If there's a data-menu-top attribute and no handleLink function, it overrides the actual anchor offset.
        else {
            menuTop = link.getAttribute(MENU_TOP_ATTR);
        }

        if(menuTop !== null) {
            //Is it a percentage offset?
            if(/p$/.test(menuTop)) {
                targetTop = (menuTop.slice(0, -1) / 100) * document.documentElement.clientHeight;
            } else {
                targetTop = +menuTop * _scale;
            }
        } else {
            var scrollTarget = document.getElementById(hash.substr(1));

            //Ignore the click if no target is found.
            if(!scrollTarget) {
                return false;
            }

            targetTop = _skrollrInstance.relativeToAbsolute(scrollTarget, 'top', 'top');

            var menuOffset = scrollTarget.getAttribute(MENU_OFFSET_ATTR);

            if(menuOffset !== null) {
                targetTop += +menuOffset;
            }
        }

        if(supportsHistory && _updateUrl && !fake) {
            history.pushState({top: targetTop}, '', hash);
        }

        var menuDuration = parseInt(link.getAttribute(MENU_DURATION_ATTR), 10);
        var animationDuration = _duration(_skrollrInstance.getScrollTop(), targetTop);

        if(!isNaN(menuDuration)) {
            animationDuration = menuDuration;
        }

        //Trigger the change if event if there's a listener.
        if(_change) {
            _change(hash, targetTop);
        }

        //Now finally scroll there.
        if(_animate && !fake) {
            _skrollrInstance.animateTo(targetTop, {
                duration: animationDuration,
                easing: _easing
            });
        } else {
            defer(function() {
                _skrollrInstance.setScrollTop(targetTop);
            });
        }

        return true;
    };

    var jumpStraightToHash = function() {
        if(window.location.hash && document.querySelector) {
            var link = document.querySelector('a[href="' + window.location.hash + '"]');

            if(!link) {
                // No link found on page, so we create one and then activate it
                link = document.createElement('a');
                link.href = window.location.hash;
            }

            handleLink(link, true);
        }
    };

    var defer = function(fn) {
        window.setTimeout(fn, 1);
    };

    /*
        Global menu function accessible through window.skrollr.menu.init.
    */
    skrollr.menu = {};
    skrollr.menu.init = function(skrollrInstance, options) {
        _skrollrInstance = skrollrInstance;

        options = options || {};

        _easing = options.easing || DEFAULT_EASING;
        _animate = options.animate !== false;
        _duration = options.duration || DEFAULT_DURATION;
        _handleLink = options.handleLink;
        _scale = options.scale || DEFAULT_SCALE;
        _complexLinks = options.complexLinks === true;
        _change = options.change;
        _updateUrl = options.updateUrl !== false;

        if(typeof _duration === 'number') {
            _duration = (function(duration) {
                return function() {
                    return duration;
                };
            }(_duration));
        }

        //Use event bubbling and attach a single listener to the document.
        skrollr.addEvent(document, 'click', handleClick);

        if(supportsHistory) {
            skrollr.addEvent(window, 'popstate', function(e) {
                var state = e.state || {};
                var top = state.top || 0;

                defer(function() {
                    _skrollrInstance.setScrollTop(top);
                });
            }, false);
        }

        jumpStraightToHash();
    };

    //Expose the handleLink function to be able to programmatically trigger clicks.
    skrollr.menu.click = function(link) {
        //We're not assigning it directly to `click` because of the second ("private") parameter.
        handleLink(link);
    };

    //Private reference to the initialized skrollr.
    var _skrollrInstance;

    var _easing;
    var _duration;
    var _animate;
    var _handleLink;
    var _scale;
    var _complexLinks;
    var _change;
    var _updateUrl;

    //In case the page was opened with a hash, prevent jumping to it.
    //http://stackoverflow.com/questions/3659072/jquery-disable-anchor-jump-when-loading-a-page
    defer(function() {
        if(window.location.hash) {
            window.scrollTo(0, 0);
        }
    });
}(document, window));

1 个答案:

答案 0 :(得分:0)

问题在于此处的缓动功能

//Now finally scroll there.
        if(_animate && !fake) {
            _skrollrInstance.animateTo(targetTop, {
                duration: animationDuration,
                easing: _easing
            });
        } else {
            defer(function() {
                _skrollrInstance.setScrollTop(targetTop);
            });
        }

        return true;

看起来,尽管Skrollr声称缓和的默认值是线性的(没有缓和),但默认值是ACTUALLY设置为sqrt(或者至少在我的情况下)。可以通过在skrollr.menu.init中强制缓和为线性或者修改skrollr.menu.js文件以从函数中删除缓动来解决此问题。这两种解决方案中的第一种解决方案更清晰,后来不会引起问题。

skrollr.menu.init(s, {
    duration: function(currentTop, targetTop) {return 20000;},
    easing: 'linear'
});