【问题标题】:ScrollTo function in AngularJSAngularJS 中的 ScrollTo 函数
【发布时间】:2013-06-21 11:07:13
【问题描述】:

我正在尝试让快速导航正常工作。它漂浮在一边。当他们点击一个链接时,它会将他们带到页面上的那个 ID。我正在关注这个guide from Treehouse。 这就是我的滚动功能:

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

我最初将它放在</body> 之前。但我似乎遇到了在编译 quickNav 之前触发的竞争条件(它上面放置了 ng-hide,不确定是否是导致它的原因 - 但它在 DOM 中)。

如果我在控制台中运行该代码块,则滚动将按预期工作。

我认为将它移动到控制器中会更有效 - 或者更有可能在指令中。但我没有运气做到这一点。 如何让这段代码与 AngularJS 一起工作?

【问题讨论】:

    标签: javascript jquery angularjs scroll anchor


    【解决方案1】:

    这是一个简单的指令,点击后会滚动到一个元素:

    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“第一个指令”开始。

    编辑:要使其滚动到由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> 滚动到具有 id 的元素。

    【讨论】:

    • 感谢您对基本指令的帮助。我已经做了几个非常基本的。我不确定如何访问 quicknav 中的 href(使用指令)以使其进行锚链接。
    • 我最终从您的编辑中删除了几行代码(主要是 if 块。)这将用于滚动到单击的元素(就像您在 plunker 中演示的那样)对吗?只是这样它会更加模块化?
    • 任何人都设法使用它并绕过导致必须双击触发“点击”的 iOS“功能”
    • @rnrneverdies 如果您将 $("body") 更改为 $("body, html"),它确实可以在 firefox 上运行
    • 为了获得最佳的跨浏览器支持,您应该使用 $("html, body").animate()
    【解决方案2】:

    如果您想使用它,这是一个更好的指令:

    您可以滚动到页面中的任何元素:

    .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 元素。

    【讨论】:

    • 为什么我需要两个指令而不是一个scroll-to-item=".selector"
    【解决方案3】:

    为了对滚动容器内的特定元素进行动画处理(固定 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");
    }
    

    【讨论】:

      【解决方案4】:

      使用$anchorScroll 的角度解决方案取自现在存档的blog post by Ben Lesh,在他贡献的this SO answer 上也有一些详细的复制(包括重写如何在路由中执行此操作):

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

      这里是 plunker,来自提供此解决方案的博客:http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview

      需要注意的是,该 plunker 的模板包含此内容,它设置了您正在使用 $anchorScroll 滚动到的 id

      <li ng-repeat="item in items" 
          id="item{{item.id}}"
      >{{item.name}</li>
      

      如果您喜欢纯 JavaScript 解决方案,这里有一个:

      在您的代码中使用父容器 ID 和目标滚动 ID 调用 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);
      }
      

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

      【讨论】:

      • 谢谢离子。更新了我的答案
      【解决方案5】:

      感谢安迪的例子,这很有帮助。由于我正在开发单页滚动并且不希望 Angular 在使用 hashbang URL 时刷新,因此我最终实施了一个稍微不同的策略。我还想保留浏览器的后退/前进操作。

      我没有使用指令和哈希,而是在 $location.search 上使用 $scope.$watch,并从那里获取目标。这给出了一个漂亮干净的锚标记

      &lt;a ng-href="#/?scroll=myElement"&gt;My element&lt;/a&gt;

      我将监视代码链接到 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 可能无法及时加载 jQuery 的 $target.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 测试

      【讨论】:

        【解决方案6】:

        我使用了 andrew joslin 的答案,效果很好,但触发了角度路线变化,这为我创造了一个看起来很跳跃的滚动。如果你想避免触发路由改变,

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

        【讨论】:

          【解决方案7】:

          另一个建议。一个带选择器的指令。

          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

          【讨论】:

            【解决方案8】:

            angular-scroll 呢,它是积极维护的,对 jQuery 没有依赖..

            【讨论】:

              【解决方案9】:

              非常明确的答案,只使用 ANGULARJS,没有任何 JQUERY 依赖

              在您的 html 底部某处 &lt;back-top&gt;some text&lt;/back-top&gt;

              在您的 html 顶部某处 &lt;div id="top"&gt;&lt;/div&gt;

              在你的 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']);
                    });
                  }
                };
              }]);
              

              【讨论】:

                【解决方案10】:

                使用元素的 ID 滚动到目标 div

                指令(Angular 1)

                angular.module("App") // Module Name
                    .directive('scrollOnClick', function () {
                        return {
                            restrict: 'A',
                            scope: {
                                scrollTo: "@"
                            },
                            link: function (scope, $elm, attrs) {
                                //var idToScroll = attrs.href;
                                $elm.on('click', function () {
                                    $('html,body').animate({ scrollTop: $(scope.scrollTo).offset().top }, "slow");
                                });
                            }
                        }
                    });
                

                HTML 代码

                <!-- Click to scroll -->
                <a scroll-on-click scroll-to="#scheduleDiv">Click here to Scroll to Div With Id ""</a>
                
                
                <!-- scrollable / target div -->
                <div id="scheduleDiv">Test scrolling ... You are able to view me on click of above anchor tag.</div>
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2014-11-24
                  • 2018-02-11
                  • 2013-08-02
                  • 1970-01-01
                  • 2010-10-24
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-07-05
                  相关资源
                  最近更新 更多