AngularJS - $ anchorScroll гладкий / тривалість


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>
Justin McCandless

1
Приємно, мені подобається ця відповідь. Але це все ж додає ще одну причину ненавидіти AngularJS, я маю на увазі, подивіться на розмір цього порівняно з JQuery scrollTo
Феліпе,

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

20

Ви також можете скористатись кутовою прокруткою, посиланням " https://github.com/durated/angular-scroll/ ". Це плавне прокручування, а також декілька функцій полегшення для отримання професійного вигляду.


1
Чи працює цей плагін на інші елементи, крім документів $? Я спробував застосувати scrollToElement до діва, щоб я міг прокрутити рядок всередині нього у подання, і це не вийшло ..
Shaunak

10

Відповідь Бретта спрацювала для мене чудово. Я вніс кілька невеликих змін у його рішення з точки зору модуляризації та тестабельності.

Ось ще один робочий приклад JsFiddle, який включає іншу версію з включеним тестуванням.

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

 anchorSmoothScroll.scrollTo(elementId, speed);

Якщо елемент є обов'язковим атрибутом для прокрутки, а швидкість є необов'язковою, де за замовчуванням 20 (як це було раніше).



2

Жодне з рішень тут насправді не робить те, що ОР спочатку просило, тобто робить $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.