Fonction ScrollTo dans AngularJS

J'essaie d'obtenir un navigateur rapide pour fonctionner correctement. Il flotte sur le côté. Quand ils cliquent sur un lien, il les prend à cette identification sur la page. Je suis en train de suivre ce guide de Treehouse . C'est ce que j'ai pour le défilement:

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

Je l'ai initialement placé avant </body> . Mais je semble avoir été confronté à une condition de course où il a été lancé avant que le quickNav ne soit compilé (il y a un ng-hide sur celui-ci, pas sûr si cela le provoque, mais c'est dans le DOM).

Si je lance ce bloc de code dans la console, le défilement fonctionne comme prévu.

Je pensais qu'il serait plus efficace de déplacer cela dans le contrôleur – ou plus probablement dans une directive. Mais je n'ai pas de chance à accomplir cela. Comment puis-je obtenir ce bloc de code pour travailler avec AngularJS?

Voici une directive simple qui se déplacera vers un élément en cliquant sur:

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

Demo: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview

Pour obtenir de l'aide pour créer des directives, consultez les vidéos à http://egghead.io , à partir du numéro 10 «première directive».

Edit : Pour le faire défiler jusqu'à un élément spécifique spécifié par un href, vérifiez 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"); }); } } }); 

Ensuite, vous pouvez l'utiliser de la sorte: <div scroll-on-click></div> pour faire défiler jusqu'à l'élément cliqué. Ou <a scroll-on-click href="#element-id"></div> pour faire défiler l'élément avec l'identifiant.

C'est une meilleure directive si vous souhaitez l'utiliser:

Vous pouvez faire défiler jusqu'à n'importe quel élément dans la page:

 .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"); }); } }}) 

L'utilisation (par exemple, cliquez sur div 'back-to-top' se déplace vers id scroll-top):

 <a id="top-scroll" name="top"></a> <div class="back-to-top" scroll-to-item scroll-to="#top-scroll"> 

Il est également pris en charge par chrome, firefox, safari et IE cause du html, élément de corps.

Pour animer un élément spécifique dans un conteneur de défilement (DIV fixe)

 /* @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"); } 

Une solution angulaire utilisant $ 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(); }; }); 

Et voici un plunk: http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview

Et si vous vous occupez d'une solution javascript pure, voici un:

Invoquez runScroll dans votre code avec ID de conteneur parent et ID de défilement cible:

 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); } 

Référence: navigateur croisé JavaScript (pas jQuery …) faire défiler jusqu'à l'animation supérieure

Merci à Andy pour l'exemple, c'était très utile. J'ai terminé la mise en œuvre d'une stratégie légèrement différente puisque j'ai développé un rouleau à une seule page et je ne voulais pas que Angular se rafraîchisse lors de l'utilisation de l'URL hashbang. Je souhaite également préserver l'action arrière / avant du navigateur.

Au lieu d'utiliser la directive et le hash, j'utilise un $ scope. $ Regarde la localisation $ location.search et obtenez la cible à partir de là. Cela donne une belle étiquette d'ancrage propre

<a ng-href="#/?scroll=myElement">My element</a>

J'ai enchaîné le code de montre dans la déclaration de mon module dans app.js comme ceci:

 .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"); }); }) 

La mise en garde avec le code ci-dessus est que si vous accédez par URL directement à partir d'une route différente, le DOM peut ne pas être chargé à temps pour l'appel $ target.offset () de jQuery. La solution consiste à imbriquer ce code dans un observateur $ viewContentLoaded. Le code final ressemble à ceci:

 .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"); }); }); }) 

Testé avec Chrome et FF

J'ai utilisé la réponse de andrew joslin, qui fonctionne très bien mais déclenché un changement de route angulaire, ce qui m'a créé un défilé à la recherche de moi. Si vous souhaitez éviter de déclencher un changement d'itinéraire,

 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; }); } } }); 

Qu'en est -il des rouleaux angulaires , il est activement maintenu et il n'y a pas de dépendance à jQuery ..

Une autre suggestion. Une directive avec sélecteur.

HTML:

 <button type="button" scroll-to="#catalogSection">Scroll To</button> 

Angulaire:

 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 }); } }); } } }); 

Notez également $ anchorScroll

Ressusciter cet ancien fil pour ajouter un correctif pour certains qui n'auraient peut-être pas pu utiliser l'une de ces directives présentées ici. Les deux corps et html ne doivent pas avoir un pourcentage de hauteur réglé, sinon aucun effet n'est observé. Une valeur automatique peut résoudre le problème sans contenir de taille de page.

 body, html { height: auto; }