Javascript ScrollTo在AngularJS中运行

Javascript ScrollTo在AngularJS中运行,javascript,jquery,angularjs,scroll,anchor,Javascript,Jquery,Angularjs,Scroll,Anchor,我在试着让导航系统正常工作。它漂浮在一边。当他们点击一个链接时,它会将他们带到页面上的那个ID。我正在关注这个。 这是我为滚动所做的: $("#quickNav a").click(function(){ var quickNavId = $(this).attr("href"); $("html, body").animate({scrollTop: $(location).offset().top}, "slow"); return false; }); 我最初把它

我在试着让导航系统正常工作。它漂浮在一边。当他们点击一个链接时,它会将他们带到页面上的那个ID。我正在关注这个。 这是我为滚动所做的:

$("#quickNav a").click(function(){
    var quickNavId = $(this).attr("href");
    $("html, body").animate({scrollTop: $(location).offset().top}, "slow");
    return false;
});
我最初把它放在
前面。但我似乎遇到了一种竞争条件,在编译quickNav之前就触发了这种情况(它有一个
ng hide
,不确定这是否是导致它的原因,但它在DOM中)

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


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

这里有一个简单的指令,单击后将滚动到一个元素:

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

有关创建指令的帮助,请查看位于的视频,从#10“第一个指令”开始

编辑:要使其滚动到a 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");
      });
    }
  }
});

然后您可以这样使用它:
滚动到单击的元素。或者
滚动到id为的元素。

感谢Andy提供的示例,这非常有用。我最终实现了一个稍微不同的策略,因为我正在开发一个单页滚动,并且不希望在使用hashbang URL时刷新。我还希望保留浏览器的后退/前进操作

我没有使用指令和散列,而是在$location.search上使用$scope.$watch,并从那里获取目标。这提供了一个非常干净的锚标签

我将watch代码链接到app.js中的my module声明,如下所示:

.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 watcher中。最终代码如下所示:

.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进行测试,如果您想使用它,这是一个更好的指令:

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

.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“返回顶部”将滚动至id滚动顶部):



chrome、firefox、safari和IE也支持它,因为html、body元素都支持它。

以便在滚动容器中为特定元素设置动画(固定DIV)


那么,它是主动维护的,并且不依赖于jQuery。

一个角度解决方案,使用
$anchorScroll
从一个现已存档的文件中获取,该文件也在他的贡献中进行了一些详细的复制(包括如何在路由中执行此操作的重写):

以下是提供此解决方案的博客中的plunker:

需要注意的重要一点是,该plunker上的模板包括以下内容,它设置了您使用
$anchorScroll
滚动到的
id

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

  • 如果您喜欢纯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);
    }
    
    函数runScroll(parentDivId,targetID){ var longdiv; longdiv=document.querySelector(“#”+parentDivId); var div3pos=document.getElementById(targetID).offsetTop; scrollTo(longdiv,div3pos,600); } 函数滚动到(元素、到、持续时间){ 如果(持续时间<0)返回; var差异=到-element.scrollTop; var perTick=差异/持续时间*10; setTimeout(函数(){ element.scrollTop=element.scrollTop+perTick; if(element.scrollTop==to)返回; 滚动至(元素,至,持续时间-10); }, 10); }
    参考资料:

    我使用了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;
          });
        }
      }
    });
    

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

    HTML:


    另外请注意,答案非常清楚,只使用ANGULARJS,没有任何JQUERY依赖

    在html的底部某处
    一些文本

    在html的顶部某处

    在您的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']);
          });
        }
      };
    }]);
    
    /**
    *@ngdoc指令
    *@name APP.directive:backTop
    
    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");
                    });
                }
            }
        });
    
    */ 有棱角的 .module('应用程序') .directive('backTop',['$location','$anchorScroll',function($location,$anchorScroll){ 返回{ 限制:'E', 替换:正确, 是的, 模板:“”, 范围:{ }, 链接:功能(范围、元素){ 元素上('click',函数(事件){ $anchorScroll(['top']); }); } }; }]);
    使用元素的ID滚动到目标div

    指令(角度1)

    HTML代码

    
    单击此处滚动至Id为“”的Div
    测试滚动…点击上面的锚标签,你就可以看到我了。
    
    感谢您对基本指令的帮助。我已经做了一些非常基本的指令。我不确定如何访问quicknav中的href(使用指令)使其进行锚定链接。我最终从编辑中删除了几行代码(主要是
    if
    块)这将用于滚动到单击的元素(如您在plunker中演示的)正确吗?只是为了使其更模块化?任何人都可以使用这一功能并绕过iOS的“功能”,该功能导致必须双击才能触发“单击”@rnrnverdies如果您将$(“body”)更改为$(“body,html”),它在firefox上确实有效为了获得最佳的跨浏览器支持,您应该使用$(“html,body”).animate()。更新了我的答案为什么我需要两个指令而不是一个
    滚动到item=“.selector”
    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;
          });
        }
      }
    });
    
    <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
                        });
                    }
                });
            }
        }
    });
    
    /**
     * @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']);
          });
        }
      };
    }]);
    
    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");
                    });
                }
            }
        });
    
    <!-- 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>