AngularJS - $ anchorScroll smooth / duration


115

En lisant les documents AngularJS, je n'ai pas compris si $anchorScrollje peux avoir une option de durée / accélération pour faciliter le défilement vers les éléments.

Il dit seulement:

$location.hash('bottom');

// call $anchorScroll()
$anchorScroll();

Je n'utilise pas jquery et je ne veux pas; Existe-t-il encore un moyen intelligent mais simple de créer ou d'étendre $anchorScrollafin de rendre le défilement plus fluide?

Réponses:


155

Malheureusement, cela n'est pas possible en utilisant $anchorScroll. Comme vous l'avez découvert, il $anchorScrolln'y a pas d'options et ne fonctionne pas avec $ngAnimate. Pour animer le défilement, vous devez utiliser votre propre service / usine ou simplement javascript.

Par souci d'auto-apprentissage, j'ai rassemblé un exemple avec un service de défilement fluide. Il existe probablement de meilleures façons de le faire, donc toute rétroaction est encouragée.

Pour faire défiler jusqu'à un élément, vous attachez un ng-click="gotoElement(ID)"à n'importe quel élément. Je pense qu'une voie encore meilleure serait d'en faire une directive.

Voici l' exemple de travail sur jsFiddle .

Mettre à jour

Il existe maintenant un certain nombre de directives tierces pour y parvenir.


11
Très agréable. Le voici en tant que directive: gist.github.com/justinmc/d72f38339e0c654437a2
Justin McCandless

@JustinMcCandless comment appelez-vous votre directive? J'ai essayé: <a ng-click="anchor-smooth-school('about');"> Environ 1 </a> <a ng-click="anchorSmoothScroll('about');"> Environ 2 < / a>
Dan

1
@Dan just do<a anchor-smooth-scroll>About 1</a> <a anchor-smooth-scroll>About 2</a>
Justin McCandless

1
Bien, j'aime cette réponse. Mais cela ajoute encore une autre raison de détester AngularJS, je veux dire, regardez la taille de cela par rapport à JQuery scrollTo
Felype

1
Pour utiliser la directive, créer un élément avec un ID (par exemple <div id="my-div">my div</div>), puis créer un lien comme celui - ci: <a anchor-smooth-scroll="my-div">visit my div</a>.
Jason Swett

20

Vous pouvez également utiliser le lien angular-scroll, " https://github.com/dured/angular-scroll/ ". C'est un défilement fluide et quelques fonctions d'accélération pour obtenir un look professionnel.


1
Ce plugin fonctionne-t-il sur d'autres éléments en dehors de $ documents? J'ai essayé d'appliquer scrollToElement à un div afin de pouvoir faire défiler une ligne à l'intérieur dans la vue, et cela n'a pas fonctionné ..
Shaunak

10

La réponse de Brett a très bien fonctionné pour moi. J'ai fait quelques petits changements sur sa solution en termes de modularisation et de testabilité.

Voici encore un autre exemple de travail sur JsFiddle qui inclut l'autre version avec tests inclus.

Pour les tests, j'utilise Karma et Jasmine. La signature a été légèrement modifiée comme suit:

 anchorSmoothScroll.scrollTo(elementId, speed);

Où l'élément est un attribut obligatoire vers lequel faire défiler et la vitesse est facultative où la valeur par défaut est 20 (comme avant).



2

Aucune des solutions présentées ici ne fait réellement ce que OP demandait à l'origine, c'est-à-dire un $anchorScrolldéfilement fluide. La différence entre les directives de défilement lisse $anchroScrollest qu'il utilise / modifie $location.hash(), ce qui peut être souhaitable dans certains cas.

Voici l'essentiel du module simple qui remplace le défilement $ anchorScroll par un défilement fluide. Il utilise la bibliothèque https://github.com/oblador/angular-scroll pour le défilement lui-même (remplacez-le par autre chose si vous le souhaitez, cela devrait être facile).

https://gist.github.com/mdvorak/fc8b531d3e082f3fdaa9
Remarque: En fait, il ne permet pas à $ anchorScroll de défiler en douceur, mais il remplace son gestionnaire pour le défilement.

Activez-le simplement en référençant le mdvorakSmoothScrollmodule dans votre application.


0

Alan, merci. Si quelqu'un est intéressé, je l'ai formaté sur la base des normes John Pappa.

(function() {

'use strict';
var moduleId = 'common';
var serviceId = 'anchorSmoothScroll';

angular
    .module(moduleId)
    .service(serviceId, anchorSmoothScroll);

anchorSmoothScroll.$inject = ['$document', '$window'];

function anchorSmoothScroll($document, $window) {

    var document = $document[0];
    var window = $window;

    var service = {
        scrollDown: scrollDown,
        scrollUp: scrollUp,
        scrollTo: scrollTo,
        scrollToTop: scrollToTop
    };
    return service;

    function getCurrentPagePosition(currentWindow, doc) {
        // Firefox, Chrome, Opera, Safari
        if (currentWindow.pageYOffset) return currentWindow.pageYOffset;
        // Internet Explorer 6 - standards mode
        if (doc.documentElement && doc.documentElement.scrollTop)
            return doc.documentElement.scrollTop;
        // Internet Explorer 6, 7 and 8
        if (doc.body.scrollTop) return doc.body.scrollTop;
        return 0;
    }

    function getElementY(doc, element) {
        var y = element.offsetTop;
        var node = element;
        while (node.offsetParent && node.offsetParent !== doc.body) {
            node = node.offsetParent;
            y += node.offsetTop;
        }
        return y;
    }

    function scrollDown(startY, stopY, speed, distance) {

        var timer = 0;

        var step = Math.round(distance / 25);
        var leapY = startY + step;

        for (var i = startY; i < stopY; i += step) {
            setTimeout('window.scrollTo(0, ' + leapY + ')', timer * speed);
            leapY += step;
            if (leapY > stopY) leapY = stopY;
            timer++;
        }
    };

    function scrollUp(startY, stopY, speed, distance) {

        var timer = 0;

        var step = Math.round(distance / 25);
        var leapY = startY - step;

        for (var i = startY; i > stopY; i -= step) {
            setTimeout('window.scrollTo(0, ' + leapY + ')', timer * speed);
            leapY -= step;
            if (leapY < stopY) leapY = stopY;
            timer++;
        }
    };

    function scrollToTop(stopY) {
        scrollTo(0, stopY);
    };

    function scrollTo(elementId, speed) {

        var element = document.getElementById(elementId);

        if (element) {
            var startY = getCurrentPagePosition(window, document);
            var stopY = getElementY(document, element);

            var distance = stopY > startY ? stopY - startY : startY - stopY;

            if (distance < 100) {
                this.scrollToTop(stopY);

            } else {

                var defaultSpeed = Math.round(distance / 100);
                speed = speed || (defaultSpeed > 20 ? 20 : defaultSpeed);

                if (stopY > startY) {
                    this.scrollDown(startY, stopY, speed, distance);
                } else {
                    this.scrollUp(startY, stopY, speed, distance);
                }
            }

        }

    };

};

})();

0

Je ne sais pas comment animer $anchorScroll. Voici comment je le fais dans mes projets:

/* Scroll to top on each ui-router state change */
$rootScope.$on('$stateChangeStart', function() {
 scrollToTop();
});

Et la fonction JS:

function scrollToTop() {
    if (typeof jQuery == 'undefined') {
        return window.scrollTo(0,0);
    } else {
        var body = $('html, body');
        body.animate({scrollTop:0}, '600', 'swing');
    }
    log("scrollToTop");
    return true;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.