AngularJS - $ anchorScroll suave / duración

115

Al leer los documentos de AngularJS, no he descubierto si $anchorScrollpuedo tener una opción de duración / aceleración para suavizar el desplazamiento a los elementos.

Solo dice:

$location.hash('bottom');

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

No uso jquery y no quiero; ¿Existe todavía una forma inteligente pero sencilla de hacer o ampliar $anchorScrollpara que el desplazamiento sea más fluido?

soy yo
fuente

Respuestas:

155

Desafortunadamente, esto no es posible usando $anchorScroll. Como descubrió $anchorScroll, no tiene opciones y no funciona con$ngAnimate . Para animar el desplazamiento, necesitaría usar su propio servicio / fábrica o simplemente javascript.

En aras del autoaprendizaje, armé un ejemplo con un servicio de desplazamiento suave. Probablemente haya mejores formas de hacer esto, por lo que se recomienda cualquier comentario.

Para desplazarse a un elemento, adjunte un ng-click="gotoElement(ID)"a cualquier elemento. Creo que una ruta aún mejor sería convertir esto en una directiva.

Aquí está el ejemplo de trabajo en jsFiddle .

Actualizar

Ahora hay una serie de directivas de terceros para lograr esto.

Brett DeWoody
fuente
11
Muy agradable. Aquí está como directiva: gist.github.com/justinmc/d72f38339e0c654437a2
Justin McCandless
@JustinMcCandless ¿cómo se llama a su directiva? Probé: <a ng-click="anchor-smooth-school('about');"> Aproximadamente 1 </a> <a ng-click="anchorSmoothScroll('about');"> Aproximadamente 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, me gusta esta respuesta. Pero esto aún agrega otra razón para odiar AngularJS, quiero decir, mire el tamaño de esto en comparación con JQuery scrollTo
Felype
1
Para utilizar la Directiva, crear un elemento con un ID (por ejemplo <div id="my-div">my div</div>) y luego crear un enlace como este: <a anchor-smooth-scroll="my-div">visit my div</a>.
Jason Swett
20

También puede utilizar el enlace de desplazamiento angular " https://github.com/durated/angular-scroll/ ". Es un desplazamiento suave también algunas funciones de aceleración para obtener un aspecto profesional.

Sagar Parikh
fuente
1
¿Este complemento funciona en otros elementos además de $ documentos? Traté de aplicar scrollToElement a un div para poder desplazar una fila dentro de él a la vista, y no funcionó ..
Shaunak
10

La respuesta de Brett funcionó muy bien para mí. Hice algunos pequeños cambios en su solución en términos de modularización y capacidad de prueba.

Aquí hay otro ejemplo de trabajo en JsFiddle que incluye la otra versión con pruebas incluidas.

Para las pruebas, estoy usando Karma y Jasmine. La firma se ha modificado ligeramente de la siguiente manera:

 anchorSmoothScroll.scrollTo(elementId, speed);

Donde elemento es un atributo obligatorio para desplazarse y la velocidad es opcional donde el valor predeterminado es 20 (como lo era antes).

Alan Souza
fuente
2

Ninguna de las soluciones aquí realmente hace lo que OP pidió originalmente, es decir, hacer que el $anchorScrolldesplazamiento sea fluido. La diferencia entre las directivas de desplazamiento suave y $anchroScrolles que usa / modifica$location.hash() , lo que puede ser deseable en algunos casos.

Aquí está la esencia del módulo simple que reemplaza el desplazamiento de $ anchorScroll con un desplazamiento suave. Utiliza https://github.com/oblador/angular-scroll biblioteca para el desplazamiento en sí (reemplácelo con otra cosa si lo desea, debería ser fácil).

https://gist.github.com/mdvorak/fc8b531d3e082f3fdaa9
Nota: En realidad, no obtiene $ anchorScroll para desplazarse sin problemas, pero reemplaza su controlador para el desplazamiento.

Habilítelo simplemente haciendo referencia al mdvorakSmoothScrollmódulo en su aplicación.

Mikee
fuente
0

Alan, gracias. Si alguien estaba interesado, lo formateé según los estándares de 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
fuente
0

No sé cómo animar $anchorScroll. Así es como lo hago en mis proyectos:

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

Y la función 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
fuente