AngularJS - $ anchorScroll smooth / duration


115

Читая документы AngularJS, я не понял, $anchorScrollможно ли использовать параметр продолжительности / замедления для плавной прокрутки элементов.

Там только сказано:

$location.hash('bottom');

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

Я не использую jquery и не хочу; есть ли еще умный, но простой способ сделать или расширить $anchorScroll, чтобы сделать прокрутку более плавной?

Ответы:


155

К сожалению, это невозможно использовать $anchorScroll. Как вы обнаружили $anchorScroll, не имеет никаких опций и не работает $ngAnimate. Чтобы анимировать прокрутку, вам нужно будет использовать собственный сервис / фабрику или просто простой javascript.

Для самообучения я собрал пример с сервисом плавной прокрутки. Вероятно, есть более эффективные способы сделать это, поэтому любая обратная связь приветствуется.

Для прокрутки к элементу вы прикрепляете ng-click="gotoElement(ID)"к любому элементу. Я думаю, что еще лучше было бы сделать это директивой.

Вот рабочий пример на jsFiddle .

Обновить

Для этого существует ряд сторонних директив.


11
Очень хорошо. Вот это как директива: gist.github.com/justinmc/d72f38339e0c654437a2
Джастин МакКэндлесс,

@JustinMcCandless, как вы называете свою директиву? Я пробовал: <a ng-click="anchor-smooth-school('about');"> Примерно 1 </a> <a ng-click="anchorSmoothScroll('about');"> Примерно 2 < / a>
Дэн

1
@Dan just do<a anchor-smooth-scroll>About 1</a> <a anchor-smooth-scroll>About 2</a>
Джастин МакКэндлесс

1
Хорошо, мне нравится этот ответ. Но это все же добавляет еще одну причину ненавидеть AngularJS, я имею в виду, посмотрите на размер этого по сравнению с JQuery scrollTo
Felype

1
Чтобы использовать директиву, создать элемент с идентификатором (например <div id="my-div">my div</div>) , а затем создать ссылку , как это: <a anchor-smooth-scroll="my-div">visit my div</a>.
Джейсон Светт

20

Вы также можете использовать angular-scroll, ссылку « https://github.com/durated/angular-scroll/ ». Это плавная прокрутка, а также несколько функций плавности, чтобы получить профессиональный вид.


1
Работает ли этот плагин с другими элементами помимо $ documents? Я попытался применить scrollToElement к div, чтобы я мог прокрутить строку внутри него в представление, и это не сработало ..
Шаунак,

10

Ответ Бретта мне очень понравился. Я внес небольшие изменения в его решение с точки зрения модульности и тестируемости.

Вот еще один рабочий пример JsFiddle, который включает другую версию с включенным тестированием.

Для тестирования я использую Карму и Жасмин. Подпись была немного изменена следующим образом:

 anchorSmoothScroll.scrollTo(elementId, speed);

Где element является обязательным атрибутом для прокрутки, а скорость необязательна, где по умолчанию 20 (как было раньше).


2

Вы также можете использовать ngSmoothScroll, ссылка: https://github.com/d-oliveros/ngSmoothScroll .

Просто включите smoothScrollмодуль как зависимость и используйте его следующим образом:

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


2

Ни одно из решений здесь на самом деле не выполняет то, что изначально просил OP, то есть не делает $anchorScrollпрокрутку плавной. Разница между директивами плавной прокрутки и тем $anchroScroll, что она использует / изменяет $location.hash(), что может быть желательно в некоторых случаях.

Вот суть простого модуля, который заменяет прокрутку $ anchorScroll плавной прокруткой. Он использует библиотеку https://github.com/oblador/angular-scroll для самой прокрутки (замените ее чем-нибудь другим, если хотите, это должно быть легко).

https://gist.github.com/mdvorak/fc8b531d3e082f3fdaa9
Примечание. На самом деле $ anchorScroll не обеспечивает плавную прокрутку, а заменяет свой обработчик прокрутки.

Включите его, просто указав mdvorakSmoothScrollмодуль в вашем приложении.


0

Алан, спасибо. Если кому интересно, форматировал по стандартам Джона Паппы.

(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

Я не знаю, как оживить $anchorScroll. Вот как я это делаю в своих проектах:

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

И функция 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;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.