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?

c'est moi
la source

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.

Brett DeWoody
la source
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.

Sagar Parikh
la source
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).

Alan Souza
la source
2

Vous pouvez également utiliser ngSmoothScroll, lien: https://github.com/d-oliveros/ngSmoothScroll .

Incluez simplement le smoothScrollmodule en tant que dépendance et utilisez-le comme ceci:

<a href="#" scroll-to="my-element-3">Click me!</a>

santiaago
la source
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.

Mikee
la source
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);
                }
            }

        }

    };

};

})();
Rentering.com
la source
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;
}
Deepak Thomas
la source