AngularJS - $ anchorScroll smooth / duration


115

Czytając dokumentację AngularJS , nie doszedłem do wniosku, czy $anchorScrollmożna mieć opcję czasu trwania / łagodzenia, aby płynnie przewijać elementy.

Mówi tylko:

$location.hash('bottom');

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

Nie używam jquery i nie chcę; czy nadal istnieje sprytny, ale prosty sposób na utworzenie lub rozszerzenie $anchorScroll, aby przewijanie było bardziej płynne?

Odpowiedzi:


155

Niestety nie jest to możliwe przy użyciu $anchorScroll. Jak odkryłeś $anchorScroll, nie ma żadnych opcji i nie działa z $ngAnimate. Aby ożywić zwój, musisz użyć własnej usługi / fabryki lub po prostu javascript.

W celu samodzielnej nauki zestawiłem przykład z usługą płynnego przewijania. Prawdopodobnie istnieją lepsze sposoby, aby to zrobić, więc zachęcamy do wyrażania opinii.

Aby przewinąć do elementu, dołączasz a ng-click="gotoElement(ID)"do dowolnego elementu. Myślę, że jeszcze lepszą drogą byłoby uczynienie tej dyrektywy dyrektywą.

Oto działający przykład na jsFiddle .

Aktualizacja

Obecnie istnieje kilka dyrektyw innych firm, które to umożliwiają.


11
Bardzo dobrze. Tutaj jest jako dyrektywa: gist.github.com/justinmc/d72f38339e0c654437a2
Justin McCandless

@JustinMcCandless jak nazywasz swoją dyrektywę? Próbowałem: <a ng-click="anchor-smooth-school('about');"> Około 1 </a> <a ng-click="anchorSmoothScroll('about');"> Około 2 < / a>
Dan,

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

1
Fajnie, podoba mi się ta odpowiedź. Ale to wciąż dodaje kolejny powód do nienawiści do AngularJS, mam na myśli, spójrz na rozmiar tego w porównaniu do JQuery scrollTo
Felype

1
Aby użyć dyrektywy, należy utworzyć element z identyfikatorem (np <div id="my-div">my div</div>), a następnie utworzyć łącze takiego: <a anchor-smooth-scroll="my-div">visit my div</a>.
Jason Swett

20

Możesz również użyć przewijania kątowego, linku „ https://github.com/durated/angular-scroll/ ”. Jest płynne przewijanie i kilka funkcji wygładzania, aby uzyskać profesjonalny wygląd.


1
Czy ta wtyczka działa na innych elementach oprócz dokumentów $? Próbowałem zastosować scrollToElement do elementu div, aby móc przewinąć wiersz w nim do widoku, ale to nie zadziałało ..
Shaunak

10

Odpowiedź Bretta zadziałała dla mnie świetnie. Wprowadziłem kilka drobnych zmian w jego rozwiązaniu pod względem modularyzacji i testowalności.

Oto kolejny działający przykład na JsFiddle, który obejmuje drugą wersję z dołączonymi testami.

Do testów używam Karmy i Jasmine. Podpis został nieznacznie zmodyfikowany w następujący sposób:

 anchorSmoothScroll.scrollTo(elementId, speed);

Gdzie element jest atrybutem obowiązkowym do przewinięcia, a prędkość jest opcjonalna, gdzie wartością domyślną jest 20 (tak jak wcześniej).



2

Żadne z przedstawionych tutaj rozwiązań w rzeczywistości nie robi tego, o co pierwotnie prosił OP, czyli $anchorScrollpłynnego przewijania. Różnica między dyrektywami płynnego przewijania $anchroScrollpolega na tym, że używa / modyfikuje $location.hash(), co może być pożądane w niektórych przypadkach.

Oto istota prostego modułu, który zastępuje przewijanie $ anchorScroll płynnym przewijaniem. Używa biblioteki https://github.com/oblador/angular-scroll do samego przewijania (zastąp ją czymś innym, jeśli chcesz, powinno być łatwe).

https://gist.github.com/mdvorak/fc8b531d3e082f3fdaa9
Uwaga: w rzeczywistości $ anchorScroll nie powoduje płynnego przewijania, ale zastępuje jego obsługę przewijania.

Włącz go po prostu odwołując się do mdvorakSmoothScrollmodułu w aplikacji.


0

Alan, dziękuję. Jeśli ktoś był zainteresowany, sformatowałem go zgodnie ze standardami Johna Pappy.

(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

Nie wiem, jak animować $anchorScroll. Oto jak robię to w moich projektach:

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

Oraz funkcja 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;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.