AngularJS – $ anchorScroll suave / duração

Lendo os documentos do AngularJS eu não descobri se $anchorScroll pode ter uma opção de duração / atenuação para suavizar a rolagem para os elementos.

Apenas diz:

 $location.hash('bottom'); // call $anchorScroll() $anchorScroll(); 

Eu não uso jquery e não quero; Existe ainda uma maneira inteligente e simples de fazer ou estender $anchorScroll para tornar a rolagem mais suave?

Infelizmente isso não é possível usando $anchorScroll . Como você descobriu, $anchorScroll não tem nenhuma opção e não funciona com $ngAnimate . Para animar o pergaminho, você precisaria usar seu próprio serviço / fábrica ou apenas um javascript direto.

Por uma questão de auto-aprendizagem eu coloquei um exemplo com um serviço de rolagem suave. Existem provavelmente melhores maneiras de fazer isso, então qualquer feedback é encorajado.

Para rolar para um elemento, você anexa um ng-click="gotoElement(ID)" a qualquer elemento. Acho que um caminho ainda melhor seria tornar isso uma diretiva.

Aqui está o exemplo de trabalho no jsFiddle .

Atualizar

Agora existem várias diretivas de terceiros para realizar isso.

Você também pode usar o link de rolagem angular, ” https://github.com/durated/angular-scroll/ “. É suave rolagem também algumas funções de facilitação para obter uma aparência profissional.

A resposta de Brett funcionou muito bem para mim. Fiz algumas pequenas alterações em sua solução em termos de modularização e testabilidade.

Aqui está outro exemplo de trabalho no JsFiddle que inclui a outra versão com testes incluídos.

Para testar, estou usando Karma e Jasmine. A assinatura foi ligeiramente modificada da seguinte forma:

  anchorSmoothScroll.scrollTo(elementId, speed); 

Em que element é um atributo obrigatório para rolagem e speed é opcional em que o padrão é 20 (como era antes).

Você também pode usar ngSmoothScroll, link: https://github.com/d-oliveros/ngSmoothScroll .

Apenas inclua o módulo smoothScroll como uma dependência e use-o da seguinte maneira:

Click me!

Nenhuma das soluções aqui faz o que o OP originalmente pediu, isto é, fazer $anchorScroll rolando suavemente. A diferença entre diretivas de rolagem suave e $anchroScroll é que ele usa / modifica $location.hash() , o que pode ser desejável em alguns casos.

Aqui está a essência do módulo simples que substitui a rolagem $ anchorScroll pela rolagem suave. Ele usa a biblioteca https://github.com/oblador/angular-scroll para a própria rolagem (substitua-a por outra coisa, se quiser, deve ser fácil).

https://gist.github.com/mdvorak/fc8b531d3e082f3fdaa9
Nota: Na verdade, ele não recebe $ anchorScroll para rolar suavemente, mas substitui seu manipulador para rolagem.

Habilite-o simplesmente referenciando o módulo mdvorakSmoothScroll em seu aplicativo.

Alan, obrigada. Se alguém estiver interessado, eu o formato com base nos padrões 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); } } } }; }; })(); 

Não estou ciente de como animar $anchorScroll . Veja como faço isso em meus projetos:

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

E a function 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; } 
Intereting Posts