ScrollTo функція в AngularJS

Я намагаюся швидко налаштовувати Nav для правильної роботи. Це плаває на боці. Коли вони натискають посилання, вони беруть їх до цього ідентифікатора на сторінці. Я виконую цей довідник від Treehouse . Це те, що я маю для прокрутки:

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

I initially placed it before the </body>. But I seem to be running into a race condition where that was firing before the quickNav compiled (it has a ng-hide placed on it, not sure if that's causing it - but it is within the DOM).

If I run that block of code in the console, then the scrolling works as expected.

I figured it'd be more effective to move this into the controller - or more likely within a directive. But I'm not having luck accomplishing that. How can I get this block of code to work with AngularJS?

65

9 Відповіді

Ось проста директива, яка буде переходити до елементу, натиснутому клацанням:

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

Щоб отримати допомогу у створенні директив, перегляньте відео за адресою http://egghead.io , починаючи з # 10 "першої директиви".

edit: To make it scroll to a specific element specified by a href, just check 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");
      });
    }
  }
});

Then you could use it like this: <div scroll-on-click></div> to scroll to the element clicked. Or </div> to scroll to element with the id.

119
додано
@AndrewJoslin Ваш приклад plunker не працює взагалі для мене на chrome на mac
додано Автор Dylanthepiguy, джерело
Хтось зміг використати це та обійти функцію iOS, що вимагає подвійного натискання, щоб викликати "клік"
додано Автор Simon H, джерело
не працює з FF.
додано Автор Emanuel Ve, джерело
Як же я отримую "Uncaught TypeError: $ не функція" при спробі вашого рішення?
додано Автор Rafael code, джерело
Дякую за допомогу з базовою директивою. Я вже зробив пару дуже базових. Я не зовсім впевнений, як я маю доступ до href в quicknav (за допомогою директиви), щоб зробити це посилання на якір.
додано Автор EnigmaRM, джерело
Я закінчився видаленням декількох рядків коду з вашого редагування (в основному просто блокування if ). Що буде використано для переходу до елементу, натиснутого на нього (як ви показали у вашому plunker) правильно? Просто так було б більш модульним?
додано Автор EnigmaRM, джерело
@rnrneverdies він працює на firefox, якщо ви зміните $ ("тіло") на $ ("body, html")
додано Автор nidal, джерело
Я не впевнений, що використання href для передачі ідентифікатора є найкращим рішенням ... Я виявив, що це трохи стрибко, оскільки браузер намагається його обробляти «звичайним» способом натискання. На мою думку, краще рішення - прив'язати щось до сфери дії, тобто. {область: elementId: '@'}, а потім та зачекайте, що замість функції посилання
додано Автор aw04, джерело
Ах, правильно. Просто скористайтеся командою attrs.href . Оновлений приклад.
додано Автор Andrew Joslin, джерело
каже, що $ elm.offest не визначено. як це може бути невизначеною цінністю.
додано Автор Wang'l Pakhrin, джерело
@Cory ви включили/завантажили JQuery?
додано Автор nmante, джерело
Щоб забезпечити кращу підтримку крос-браузера, ви повинні використовувати $ ("html, body"). Animate ()
додано Автор Cory, джерело

Це краща директива, якщо ви хочете її використовувати:

ви можете перейти до будь-якого елемента на сторінці:

.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):


<div class="back-to-top" scroll-to-item scroll-to="#top-scroll"> 

It's also supported by chrome,firefox,safari and IE cause of the html,body element .

31
додано
Чому мені потрібні дві директиви замість одного scroll-to-item = ". Selector" ?
додано Автор Undefitied, джерело

Для анімації до певного елемента всередині контейнера прокрутки (фіксований 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");
}
21
додано

Кутовий розв'язок за допомогою $ 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();
  };
});

And here is a plunk: 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);
}

Reference: Cross browser JavaScript (not jQuery...) scroll to top animation

6
додано
Спасибі людині. Це корисно. :-)
додано Автор Ionic, джерело
Спасибі іонному. Оновлено мою відповідь
додано Автор Hasteq, джерело

Спасибі Енді на прикладі, це було дуже корисно. Я закінчив реалізацію дещо іншої стратегії, оскільки я розробляю прокрутку на одній сторінці і не хочу, щоб Angular оновлювався при використанні хешбанг-URL-адреси. Я також хочу зберегти назад/вперед дії браузера.

Замість того, щоб використовувати директиву та хеш, я використовую $ $ $ scope $. Годинник у $ location.search і отримав ціль туди. Це дає хороший чіткий ярлик

Мій елемент

Я прив'язав код годинника до моєї декларації модуля у 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");
   });
})

Застереження з наведеним вище кодом полягає в тому, що якщо ви отримуєте доступ до URL безпосередньо з іншого маршруту, DOM може не завантажуватися вчасно для виклику $ target.offset() у jQuery. Рішення полягає в тому, щоб вставити цей код у веб-переглядач $ 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

4
додано

Я використав answer andrew anslin, який чудово працює, але спричинив зміну кутового маршруту, що створило для мене стрибкоподібний прокрут. Якщо ви хочете уникнути ініціювання зміни маршруту,

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
додано

Інше пропозиція. Одна директива з селектором.

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

Also notice $anchorScroll

1
додано

Що стосується кутова прокрутка , її активно підтримують і немає жодної залежності від jQuery.

1
додано

дуже чітка відповідь, використовуючи тільки ANGULARJS, ніякий jQuery не залежить

in your html somewhere on the bottom some text

у своєму html де-не-що у верхній частині <div id = "top"> </div>

у твоїх джс:

/**
 * @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']);
      });
    }
  };
}]);
0
додано
також читайте джерело docs.angularjs.org/api/ng/service/$anchorScroll
додано Автор miukki, джерело
ІТ КПІ - JavaScript
ІТ КПІ - JavaScript
504 учасників

співтовариство javascript розробників в Telegram