Fonction ScrollTo en AngularJS

j'essaie d'obtenir un nav rapide pour fonctionner correctement. Flotter sur le côté. Quand ils cliquent sur un lien, il les emmène à cette ID sur la page. Je suis 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 d'abord placé avant le </body> . Mais il me semble que je suis dans une condition de course où il était en feu avant que le quickNav compilé (il a un ng-hide placé sur elle, pas sûr si cela en est la cause - mais il est dans le DOM).

Si j'exécute ce bloc de code dans la console, puis le défilement fonctionne comme prévu.

je me suis dit qu'il serait plus efficace de transférer cette information dans le contrôleur - ou plus probablement dans une directive. Mais je n'ai pas la chance d'accomplir ça. Comment faire fonctionner ce bloc de code avec AngularJS?

65
demandé sur EnigmaRM 2013-06-24 23:58:33

9 réponses

Voici une directive simple qui fera défiler vers un élément du clic:

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

Démo: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview

pour obtenir de l'aide sur la création de directives, consultez les vidéos à http://egghead.io , à partir du N ° 10"première directive".

edit : pour le faire défiler vers un élément spécifique spécifié par un href, il suffit cochez la case 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 comme ceci: <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 vers l'élément avec l'id.

119
répondu Andrew Joslin 2013-06-25 17:46:00

c'est une meilleure directive au cas où vous voudriez l'utiliser:

vous pouvez faire défiler jusqu'à n'importe quel élément de 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");
            });                                                                              
        }                                                                                    
    }})     

d'Utilisation (par exemple, cliquez sur les div " de retour au top de passer à l'id de défilement en haut):

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

il est également supporté par chrome,firefox,safari et IE cause du html,élément de corps .

31
répondu Liad Livnat 2014-07-04 15:36:47

afin d'animer à un élément spécifique à l'intérieur d'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");
}
21
répondu teter 2015-02-17 09:25:22

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 morceau: http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview

et si vous vous souciez d'une solution javascript pure, en voici une:

Invoquer runScroll dans votre code avec conteneur parent de l'id et de la cible de défilement id:

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

la Référence: de la Croix-navigateur JavaScript (pas de jQuery...) faites défiler vers le haut animation

6
répondu Hasteq 2017-05-23 11:54:48

Merci Andy pour l'exemple, cela a été très utile. J'ai mis fin à la mise en œuvre d'une stratégie légèrement différente puisque je suis en train de développer un parchemin d'une seule page et que je ne voulais pas que Angular se rafraîchisse en utilisant L'URL HASHBANG. Je veux aussi préserver l'action arrière/avant du navigateur.

au lieu d'utiliser la directive et le hachage, j'utilise un $scope.$regarder sur l'emplacement$.cherche, et obtient la cible 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 la montre à la déclaration de mon module dans app.js:

.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 ne peut pas être chargé à temps pour la cible $de jQuery.offset (). La solution est d'insérer ce code dans un watcher $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

4
répondu Marc Gibbons 2013-09-02 19:27:46

j'ai utilisé la réponse d'andrew joslin, qui fonctionne très bien mais a déclenché un changement de route angulaire, qui a créé un parchemin à la recherche de sursaut pour moi. Si vous voulez é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;
      });
    }
  }
});
4
répondu danyamachine 2015-07-26 06:57:19

Qu'en est-il de " Angular-scroll , il est activement maintenu et il n'y a pas de dépendance à jQuery..

1
répondu Marwen Trabelsi 2015-05-19 08:31:56

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

Aussi avis $anchorScroll

1
répondu Undefitied 2016-09-07 06:47:37

réponse très claire, en utilisant juste ANGULARJS, aucun JQUERY dépend

dans votre html quelque part en bas <back-top>some text</back-top>

dans votre html quelque part en haut <div id="top"></div>

dans votre js:

/**
 * @ngdoc directive
 * @name APP.directive:backTop
 <pre>
<back-top></back-top>
 </pre>
 */


angular
.module('APP')
.directive('backTop', ['$location', '$anchorScroll' ,function($location, $anchorScroll) {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    template: '<span class=\'btn btn-mute pull-right\'><i class=\'glyphicon glyphicon-chevron-up\'></i><ng-transclude></ng-transclude></span>',
    scope: {
    },
    link: function(scope, element) {
      element.on('click', function(event) {
        $anchorScroll(['top']);
      });
    }
  };
}]);
0
répondu miukki 2017-12-28 07:21:51