AngularJS - $ anchorScroll smooth / duration


115

Leggendo i documenti di AngularJS non ho capito se $anchorScrollpuò avere un'opzione di durata / andamento per regolare lo scorrimento degli elementi.

Dice solo:

$location.hash('bottom');

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

Non uso jquery e non voglio farlo; c'è ancora un modo intelligente ma semplice per creare o estendere $anchorScrollper rendere lo scorrimento più fluido?

Risposte:


155

Purtroppo questo non è possibile utilizzando $anchorScroll. Come hai scoperto $anchorScrollnon ha opzioni e non funziona con $ngAnimate. Per animare lo scorrimento è necessario utilizzare il proprio servizio / fabbrica o semplicemente javascript.

Per motivi di autoapprendimento ho messo insieme un esempio con un servizio di scorrimento fluido. Probabilmente ci sono modi migliori per farlo, quindi qualsiasi feedback è incoraggiato.

Per scorrere fino a un elemento, allega un ng-click="gotoElement(ID)"a qualsiasi elemento. Penso che un percorso ancora migliore sarebbe quello di rendere questa direttiva una direttiva.

Ecco l' esempio funzionante su jsFiddle .

Aggiornare

Esistono ora numerose direttive di terze parti per eseguire questa operazione.


11

@JustinMcCandless come chiami la tua direttiva? Ho provato: <a ng-click="anchor-smooth-school('about');"> Circa 1 </a> <a ng-click="anchorSmoothScroll('about');"> Circa 2 < / a>
Dan

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

1
Bello, mi piace questa risposta. Ma questo aggiunge ancora un altro motivo per odiare AngularJS, voglio dire, guarda le dimensioni di questo rispetto a JQuery scrollTo
Felype

1
Per utilizzare la direttiva, creare un elemento con un ID (ad esempio <div id="my-div">my div</div>) e quindi creare un link come questo: <a anchor-smooth-scroll="my-div">visit my div</a>.
Jason Swett

20

Puoi anche usare lo scorrimento angolare, link " https://github.com/dazed/angular-scroll/ ". Lo scorrimento è fluido e anche alcune funzioni di facilitazione per ottenere un aspetto professionale.


1
Questo plugin funziona su altri elementi oltre a $ documenti? Ho provato ad applicare scrollToElement a un div in modo da poter scorrere una riga al suo interno nella vista e non ha funzionato ..
Shaunak

10

La risposta di Brett ha funzionato alla grande per me. Ho apportato alcune piccole modifiche alla sua soluzione in termini di modularizzazione e testabilità.

Ecco un altro esempio funzionante su JsFiddle che include l'altra versione con test inclusi.

Per i test, sto usando Karma e Jasmine. La firma è stata leggermente modificata come segue:

 anchorSmoothScroll.scrollTo(elementId, speed);

Dove element è un attributo obbligatorio su cui scorrere e la velocità è opzionale dove il valore predefinito è 20 (come prima).



2

Nessuna delle soluzioni qui in realtà fa ciò che OP originariamente richiesto, cioè, rende lo $anchorScrollscorrimento fluido. La differenza tra le direttive di scorrimento uniforme $anchroScrollè che utilizza / modifica $location.hash(), il che può essere desiderabile in alcuni casi.

Ecco l'essenza di un modulo semplice che sostituisce $ anchorScroll scrolling con scorrimento fluido. Usa la libreria https://github.com/oblador/angular-scroll per lo scorrimento stesso (sostituiscilo con qualcos'altro se vuoi, dovrebbe essere facile).

https://gist.github.com/mdvorak/fc8b531d3e082f3fdaa9
Nota: in realtà non fa scorrere $ anchorScroll in modo fluido, ma sostituisce il suo gestore per lo scorrimento.

Abilitalo semplicemente facendo riferimento al mdvorakSmoothScrollmodulo nella tua applicazione.


0

Alan, grazie. Se qualcuno fosse interessato, l'ho formattato in base agli standard di 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

Non sono a conoscenza di come animare $anchorScroll. Ecco come lo faccio nei miei progetti:

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

E la funzione 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.