Função ScrollTo no AngularJS

Estou tentando fazer uma navegação rápida funcionar corretamente. Está flutuando ao lado. Quando clicam em um link, ele leva para esse ID na página. Estou seguindo este guia da Treehouse . Isto é o que eu tenho para a rolagem:

$("#quickNav a").click(function(){ var quickNavId = $(this).attr("href"); $("html, body").animate({scrollTop: $(location).offset().top}, "slow"); return false; }); 

Eu inicialmente coloquei antes do . Mas eu pareço estar correndo em uma condição de corrida onde isso foi triggersdo antes do quickNav compilado (ele tem um ng-hide colocado nele, não tenho certeza se isso está causando isso – mas está dentro do DOM).

Se eu executar esse bloco de código no console, a rolagem funcionará conforme o esperado.

Eu imaginei que seria mais eficaz mover isso para o controlador – ou mais provavelmente dentro de uma diretiva. Mas eu não estou tendo sorte para isso. Como posso obter esse bloco de código para trabalhar com o AngularJS?

Aqui está uma diretiva simples que irá rolar para um elemento ao clicar:

 myApp.directive('scrollOnClick', function() { return { restrict: 'A', link: function(scope, $elm) { $elm.on('click', function() { $("body").animate({scrollTop: $elm.offset().top}, "slow"); }); } } }); 

Demonstração: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview

Para ajuda na criação de diretivas, confira os vídeos em http://egghead.io , começando em # 10 “primeira diretiva”.

edit : Para fazê-lo rolar para um elemento específico especificado por um href, basta verificar attrs.href .

 myApp.directive('scrollOnClick', function() { return { restrict: 'A', link: function(scope, $elm, attrs) { var idToScroll = attrs.href; $elm.on('click', function() { var $target; if (idToScroll) { $target = $(idToScroll); } else { $target = $elm; } $("body").animate({scrollTop: $target.offset().top}, "slow"); }); } } }); 

Então você poderia usá-lo assim:

para rolar até o elemento clicado. Ou para rolar para o elemento com o ID.

Esta é uma diretiva melhor caso você queira usá-la:

você pode rolar para qualquer elemento na página:

 .directive('scrollToItem', function() { return { restrict: 'A', scope: { scrollTo: "@" }, link: function(scope, $elm,attr) { $elm.on('click', function() { $('html,body').animate({scrollTop: $(scope.scrollTo).offset().top }, "slow"); }); } }}) 

Uso (por exemplo, clique no div ‘back-to-top’ irá rolar para o id scroll-top):

  

Também é suportado pelo chrome, firefox, safari e IE, causa do html, body element.

Para animar um elemento específico dentro de um contêiner de rolagem (DIV fixo)

 /* @param Container(DIV) that needs to be scrolled, ID or Div of the anchor element that should be scrolled to Scrolls to a specific element in the div container */ this.scrollTo = function(container, anchor) { var element = angular.element(anchor); angular.element(container).animate({scrollTop: element.offset().top}, "slow"); } 

Uma solução angular usando $ anchorScroll http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html :

 app.controller('MainCtrl', function($scope, $location, $anchorScroll) { var i = 1; $scope.items = [{ id: 1, name: 'Item 1' }]; $scope.addItem = function (){ i++; //add the item. $scope.items.push({ id: i, name: 'Item ' + i}); //now scroll to it. $location.hash('item' + i); $anchorScroll(); }; }); 

E aqui está um plunk: http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview

E se você se importa com uma solução de javascript pura, aqui está uma:

Invoque runScroll em seu código com o ID do contêiner pai e o ID de rolagem de destino:

 function runScroll(parentDivId,targetID) { var longdiv; longdiv = document.querySelector("#" + parentDivId); var div3pos = document.getElementById(targetID).offsetTop; scrollTo(longdiv, div3pos, 600); } function scrollTo(element, to, duration) { if (duration < 0) return; var difference = to - element.scrollTop; var perTick = difference / duration * 10; setTimeout(function () { element.scrollTop = element.scrollTop + perTick; if (element.scrollTop == to) return; scrollTo(element, to, duration - 10); }, 10); } 

Referência: Cruz navegador JavaScript (não jQuery ...) rolar para cima animação

Obrigado Andy pelo exemplo, isso foi muito útil. Acabei de implementar uma estratégia um pouco diferente, já que estou desenvolvendo uma rolagem de página única e não queria que o Angular fosse atualizado ao usar o URL do hashbang. Eu também quero preservar a ação back / forward do navegador.

Em vez de usar a diretiva e o hash, estou usando $ escopo. $ Watch no $ location.search e obtendo o destino de lá. Isso dá uma tag âncora limpa

My element

Eu acorrentado o código de relógio para a declaração do meu módulo em app.js da seguinte forma:

 .run(function($location, $rootScope) { $rootScope.$watch(function() { return $location.search() }, function(search) { var scrollPos = 0; if (search.hasOwnProperty('scroll')) { var $target = $('#' + search.scroll); scrollPos = $target.offset().top; } $("body,html").animate({scrollTop: scrollPos}, "slow"); }); }) 

A ressalva com o código acima é que se você acessar por URL diretamente de uma rota diferente, o DOM não pode ser carregado a tempo para a chamada $ target.offset () do jQuery. A solução é aninhar esse código em um observador $ viewContentLoaded. O código final é algo como isto:

 .run(function($location, $rootScope) { $rootScope.$on('$viewContentLoaded', function() { $rootScope.$watch(function() { return $location.search() }, function(search) { var scrollPos = 0 if (search.hasOwnProperty('scroll')) { var $target = $('#' + search.scroll); var scrollPos = $target.offset().top; } $("body,html").animate({scrollTop: scrollPos}, "slow"); }); }); }) 

Testado com o Chrome e o FF

Eu usei a resposta de Andrew joslin, que funciona muito bem, mas desencadeou uma mudança de rota angular, que criou um pergaminho de aparência nervosa para mim. Se você quiser evitar o acionamento de uma mudança de rota,

 myApp.directive('scrollOnClick', function() { return { restrict: 'A', link: function(scope, $elm, attrs) { var idToScroll = attrs.href; $elm.on('click', function(event) { event.preventDefault(); var $target; if (idToScroll) { $target = $(idToScroll); } else { $target = $elm; } $("body").animate({scrollTop: $target.offset().top}, "slow"); return false; }); } } }); 

E quanto ao scroll angular , ele é mantido ativamente e não há dependência para o jQuery.

Outra sugestão. Uma diretiva com seletor.

HTML:

  

Angular:

 app.directive('scrollTo', function () { return { restrict: 'A', link: function (scope, element, attrs) { element.on('click', function () { var target = $(attrs.scrollTo); if (target.length > 0) { $('html, body').animate({ scrollTop: target.offset().top }); } }); } } }); 

Observe também $ anchorScroll

resposta muito clara, usando apenas ANGULARJS, nenhum JQUERY depende

no seu html em algum lugar na parte inferior some text

no seu html em algum lugar no topo

no seu js:

 /** * @ngdoc directive * @name APP.directive:backTop 
  

*/ angular .module('APP') .directive('backTop', ['$location', '$anchorScroll' ,function($location, $anchorScroll) { return { restrict: 'E', replace: true, transclude: true, template: '', scope: { }, link: function(scope, element) { element.on('click', function(event) { $anchorScroll(['top']); }); } }; }]);

Intereting Posts