Функция ScrollTo в AngularJS



Я пытаюсь получить быстрый навигатор, чтобы работать правильно. Он плавает на боку. Когда они нажимают на ссылку, она приводит их к этому идентификатору на странице. Я следую за этим руководство от Treehouse.
Это то, что у меня есть для прокрутки:



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


Я изначально поместил его перед </body>. Но я, кажется, впадаю в состояние гонки, где это стреляло до того, как quickNav скомпилирован (у него есть ng-hide помещенный на него, не уверен, что это вызывает его - но это так в дом).



Если я запускаю этот кусок кода в консоли, то прокрутка работает, как ожидалось.



Я подумал, что было бы более эффективно переместить это в контроллер - или, скорее всего, в директиве. Но мне не везет с этим делом. как я могу получить этот блок кода для работы с AngularJS?

710   9  

9 ответов:

вот простая директива, которая будет прокручиваться до элемента по щелчку:

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

демо: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview

для помощи в создании директив, проверьте видео на http://egghead.io, начиная с #10 "Первая директива".

edit: чтобы выполнить прокрутку до определенного элемента, указанного в href, просто проверьте 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");
      });
    }
  }
});

тогда вы могли бы использовать его как это: <div scroll-on-click></div> для прокрутки до элемента нажата. Или <a scroll-on-click href="#element-id"></div> для прокрутки до элемента с идентификатором.

Это лучшая директива, если вы хотите ее использовать:

вы можете перейти к любому элементу на странице:

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

использование (например, нажмите на div 'back-to-top' будет прокручиваться до id scroll-top):

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

Он также поддерживается chrome, firefox, safari и IE причиной html, body элемента .

для анимации определенного элемента внутри контейнера прокрутки (фиксированный DIV)

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

угловое решение с использованием $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();
  };
});

и вот плюх:http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview

и если вы заботитесь о чистом решении javascript, вот один:

вызовите runScroll в коде с идентификатором родительского контейнера и целевым идентификатором прокрутки:

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

ссылки: Кросс-браузер JavaScript (не jQuery...) прокрутите до верхней анимации

спасибо Энди за пример, это было очень полезно. Я закончил реализацию немного другой стратегии, так как я разрабатываю одностраничный свиток и не хочу, чтобы Angular обновлялся при использовании URL-адреса hashbang. Я также хочу сохранить назад / вперед действие браузера.

вместо использования директивы и хэша, я использую $ scope.$ смотрите на $location.поиск и получение цели оттуда. Это дает хороший чистый якорь тег

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

Я приковал код часов к объявлению моего модуля в приложении.Яш вот так:

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

предостережение с приведенным выше кодом заключается в том, что если вы получаете доступ по URL-адресу непосредственно с другого маршрута, DOM не может быть загружен вовремя для $target jQuery.offset () вызов. Решение состоит в том, чтобы вложить этот код в наблюдатель $viewContentLoaded. Окончательный код выглядит примерно так:

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

протестировано с Chrome и FF

я использовал ответ Эндрю Джослина, который отлично работает, но вызвал угловое изменение маршрута, что создало для меня нервный свиток. Если вы хотите избежать изменения маршрута,

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

а как же угловое-свиток, он активно поддерживается и нет никакой зависимости от jQuery..

другое предложение. Одна директива с селектором.

HTML:

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

Угловое:

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

и уведомления $anchorScroll

очень четкий ответ, используя только ANGULARJS, никакой JQUERY не зависит

в вашем html где-то внизу <back-top>some text</back-top>

в вашем html где-то сверху <div id="top"></div>

в вашем 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']);
      });
    }
  };
}]);

Comments

    Ничего не найдено.