【问题标题】:Changing route doesn't scroll to top in the new page更改路线不会在新页面中滚动到顶部
【发布时间】:2014-01-30 02:42:43
【问题描述】:

当路线改变时,我发现了一些不受欢迎的行为,至少对我来说是这样。 在教程的第11步http://angular.github.io/angular-phonecat/step-11/app/#/phones 你可以看到手机列表。如果您滚动到底部并单击最新的一个,您会看到滚动不在顶部,而是在中间。

我也在我的一个应用程序中发现了这个,我想知道如何让它滚动到顶部。我可以手动完成,但我认为应该有其他优雅的方式来做到这一点,我不知道。

那么,当路线改变时,有没有一种优雅的方式滚动到顶部?

【问题讨论】:

    标签: javascript angularjs scroll angularjs-routing


    【解决方案1】:

    简单的解决方案,在启用的主路由模块中添加scrollPositionRestoration
    像这样:

    const routes: Routes = [
    
     {
       path: 'registration',
       loadChildren: () => RegistrationModule
    },
    ];
    
     @NgModule({
      imports: [
       RouterModule.forRoot(routes,{scrollPositionRestoration:'enabled'})
      ],
     exports: [
     RouterModule
     ]
     })
      export class AppRoutingModule { }
    

    【讨论】:

      【解决方案2】:

      这对我有用,包括自动滚动

      <div class="ngView" autoscroll="true" >

      【讨论】:

        【解决方案3】:

        我终于得到了我需要的东西。

        我需要滚动到顶部,但希望一些过渡不要

        您可以在逐个路由级别进行控制。
        我正在通过@wkonkel 结合上述解决方案,并在一些路由声明中添加一个简单的noScroll: true 参数。然后我在过渡中抓住了这一点。

        总而言之:这会在新过渡时浮动到页面顶部,在 Forward / Back 过渡时不会浮动到顶部,并且它允许您在必要时覆盖此行为。

        代码:(以前的解决方案加上一个额外的 noScroll 选项)

          // hack to scroll to top when navigating to new URLS but not back/forward
          let wrap = function(method) {
            let orig = $window.window.history[method];
            $window.window.history[method] = function() {
              let retval = orig.apply(this, Array.prototype.slice.call(arguments));
              if($state.current && $state.current.noScroll) {
                return retval;
              }
              $anchorScroll();
              return retval;
            };
          };
          wrap('pushState');
          wrap('replaceState');
        

        将其放入您的 app.run 块并注入 $state... myApp.run(function($state){...})

        然后,如果您不想滚动到页面顶部,请创建这样的路由:

        .state('someState', {
          parent: 'someParent',
          url: 'someUrl',
          noScroll : true // Notice this parameter here!
        })
        

        【讨论】:

          【解决方案4】:

          提供的答案都没有解决我的问题。我在视图之间使用动画,并且滚动总是在动画之后发生。我发现在动画之前滚动到顶部的解决方案是以下指令:

          yourModule.directive('scrollToTopBeforeAnimation', ['$animate', function ($animate) {
              return {
                  restrict: 'A',
                  link: function ($scope, element) {
                      $animate.on('enter', element, function (element, phase) {
          
                          if (phase === 'start') {
          
                              window.scrollTo(0, 0);
                          }
          
                      })
                  }
              };
          }]);
          

          我将它插入到我的视图中如下:

          <div scroll-to-top-before-animation>
              <div ng-view class="view-animation"></div>
          </div>
          

          【讨论】:

            【解决方案5】:

            这段代码对我很有用 .. 我希望它对你也很有效 .. 您所要做的就是将 $anchorScroll 注入您的运行块并将侦听器函数应用于 rootScope,就像我在下面的示例中所做的那样..

             angular.module('myAngularApp')
            .run(function($rootScope, Auth, $state, $anchorScroll){
                $rootScope.$on("$locationChangeSuccess", function(){
                    $anchorScroll();
                });
            

            Angularjs Module的调用顺序如下:

            1. app.config()
            2. app.run()
            3. directive's compile functions (if they are found in the dom)
            4. app.controller()
            5. directive's link functions (again, if found)

            RUN BLOCK 在注入器创建后执行并用于启动应用程序。这意味着当您重定向到新的路由视图时,运行块中的侦听器会调用

            $anchorScroll()

            你现在可以看到滚动开始到顶部,新的路由视图:)

            【讨论】:

            • 最后,一个使用粘性标题的解决方案!谢谢!
            【解决方案6】:

            聚会有点晚了,但我已经尝试了所有可能的方法,但都没有正常工作。这是我的优雅解决方案:

            我使用一个控制器,它通过 ui-router 管理我的所有页面。它允许我将未经过身份验证或验证的用户重定向到适当的位置。大多数人将他们的中间件放在他们应用程序的配置中,但我需要一些 http 请求,因此全局控制器对我来说效果更好。

            我的 index.html 看起来像:

            <main ng-controller="InitCtrl">
                <nav id="top-nav"></nav>
                <div ui-view></div>
            </main>
            

            我的 initCtrl.js 看起来像:

            angular.module('MyApp').controller('InitCtrl', function($rootScope, $timeout, $anchorScroll) {
                $rootScope.$on('$locationChangeStart', function(event, next, current){
                    // middleware
                });
                $rootScope.$on("$locationChangeSuccess", function(){
                    $timeout(function() {
                        $anchorScroll('top-nav');
                   });
                });
            });
            

            我已经尝试了所有可能的选项,这种方法效果最好。

            【讨论】:

            • 这对我来说是唯一使用 angular-material 的,将 id="top-nav" 放置在正确的元素上也很重要。
            【解决方案7】:

            使用 angularjs UI Router,我正在做的是这样的:

                .state('myState', {
                    url: '/myState',
                    templateUrl: 'app/views/myState.html',
                    onEnter: scrollContent
                })
            

            与:

            var scrollContent = function() {
                // Your favorite scroll method here
            };
            

            它在任何页面上都不会失败,而且它不是全局的。

            【讨论】:

            • 好主意,您可以使用以下方法缩短它:onEnter: scrollContent
            • 你在写// Your favorite scroll method here的地方放了什么?
            • 好时机:我在原始代码中的这条评论上方两行,尝试ui-router-title。我用$('html, body').animate({ scrollTop: -10000 }, 100);
            • 哈哈,太好了!奇怪的是,它并不总是对我有用。我有一些视图太短以至于没有滚动条,还有两个视图有滚动条,当我在每个视图上放置onEnter: scrollContent 时,它只适用于第一个视图/路线,而不是第二个。奇怪。
            • 我不确定,不,它只是不应该滚动到顶部。当我在“路线”之间单击时,其中一些仍在滚动到 ng-view 所在的位置,而不是封闭页面的绝对顶部。这有意义吗?
            【解决方案8】:

            我找到了这个解决方案。如果您转到新视图,该函数将被执行。

            var app = angular.module('hoofdModule', ['ngRoute']);
            
                app.controller('indexController', function ($scope, $window) {
                    $scope.$on('$viewContentLoaded', function () {
                        $window.scrollTo(0, 0);
                    });
                });
            

            【讨论】:

              【解决方案9】:

              如果你使用 ui-router,你可以使用(运行时)

              $rootScope.$on("$stateChangeSuccess", function (event, currentState, previousState) {
                  $window.scrollTo(0, 0);
              });
              

              【讨论】:

              • 我知道这应该可行,我广泛使用“$stateChangeSuccess”,但由于某种原因 $window.scrollTo(0,0) 无法使用。
              【解决方案10】:

              在尝试ui-view autoscroll=true$stateChangeStart$locationChangeStart$uiViewScrollProvider.useAnchorScroll()$provide('$uiViewScroll', ...) 和许多其他组合的每个组合一两个小时后,我无法滚动到顶部-新页面按预期工作。

              这最终对我有用。它捕获 pushState 和 replaceState 并且仅在导航到新页面时更新滚动位置(后退/前进按钮保留其滚动位置):

              .run(function($anchorScroll, $window) {
                // hack to scroll to top when navigating to new URLS but not back/forward
                var wrap = function(method) {
                  var orig = $window.window.history[method];
                  $window.window.history[method] = function() {
                    var retval = orig.apply(this, Array.prototype.slice.call(arguments));
                    $anchorScroll();
                    return retval;
                  };
                };
                wrap('pushState');
                wrap('replaceState');
              })
              

              【讨论】:

              • 这非常适合我的用例。我正在使用带有嵌套视图的 Angular UI-Router(深几级)。谢谢!
              • 仅供参考 - 您需要在 Angular 中处于 HTML5 模式才能使用 pushState:$locationProvider.html5Mode(true); @wkronkel 在不使用 Angular 中的 HTML5 模式时有没有办法做到这一点?由于 html 5 模式处于活动状态,导致页面重新加载引发 404 错误
              • @britztopher 您可以挂钩内置事件并维护自己的历史记录,对吧?
              • 您将此.run 附加到哪里? app 对象的角度?
              • @Philll_t:是的,run 函数是每个角度模块对象都可用的方法。
              【解决方案11】:

              以上所有答案都破坏了预期的浏览器行为。大多数人想要的是,如果它是一个“新”页面,它会滚动到顶部,但如果你通过后退(或前进)按钮返回到上一个位置。

              如果您采用 HTML5 模式,那么这很容易(尽管我相信一些聪明的人会想出如何让它更优雅!):

              // Called when browser back/forward used
              window.onpopstate = function() { 
                  $timeout.cancel(doc_scrolling); 
              };
              
              // Called after ui-router changes state (but sadly before onpopstate)
              $scope.$on('$stateChangeSuccess', function() {
                  doc_scrolling = $timeout( scroll_top, 50 );
              
              // Moves entire browser window to top
              scroll_top = function() {
                  document.body.scrollTop = document.documentElement.scrollTop = 0;
              }
              

              它的工作方式是路由器假设它会滚动到顶部,但会延迟一点,让浏览器有机会完成。如果浏览器随后通知我们更改是由于后退/前进导航引起的,它会取消超时,并且永远不会发生滚动。

              我使用原始document 命令滚动,因为我想移动到窗口的整个顶部。如果您只想让您的ui-view 滚动,请使用上述技术在您控制my_var 的位置设置autoscroll="my_var"。但我认为,如果您要以“新”身份访问页面,大多数人会希望滚动整个页面。

              以上使用 ui-router,但您可以通过将$routeChangeSuccess 替换为$stateChangeSuccess 来使用 ng-route。

              【讨论】:

              • 你如何实现这个?您会将其放在常规的 angular-ui 路由代码中,如下所示? var routerApp = angular.module('routerApp', ['ui.router']); routerApp.config(function($stateProvider, $urlRouterProvider, $locationProvider) { $urlRouterProvider.otherwise('/home'); $locationProvider.html5Mode(false).hashPrefix(""); $stateProvider // HOME STATES AND NESTED VIEWS ======================================== .state('home', { url: '/home', templateUrl: 'partial-home.html' }) });
              • hmmm... 没用 :-( 它只会杀死应用程序。.state('web', { url: '/webdev', templateUrl: 'partial-web.html', controller: function($scope) { $scope.clients = ['client1', 'client2', 'client3']; // I put it here } }) 我只是在学习这些东西,也许我错过了一些东西 :D
              • @AgentZebra 至少,控制器需要将 $timeout 作为输入(因为我的代码引用了它),但也许更重要的是,我提到的控制器需要在高于单个状态的级别(您可以在顶级控制器中包含语句)。最初的 AngularJS 学习曲线确实非常困难;祝你好运!
              【解决方案12】:

              这是我(看似)稳健、完整且(相当)简洁的解决方案。它使用缩小兼容样式(以及对您的模块的 angular.module(NAME) 访问)。

              angular.module('yourModuleName').run(["$rootScope", "$anchorScroll" , function ($rootScope, $anchorScroll) {
                  $rootScope.$on("$locationChangeSuccess", function() {
                              $anchorScroll();
                  });
              }]);
              

              PS我发现自动滚动的东西不管设置为true还是false都没有效果。

              【讨论】:

              • 嗯..这会将视图滚动到顶部首先,然后屏幕上的视图会为我改变。
              • 我正在寻找的清洁解决方案。如果你点击“返回”,它会带你回到你离开的地方——这对某些人来说可能是不可取的,但在我的情况下我喜欢它。
              【解决方案13】:

              将 autoScroll 设置为 true 对我来说不是诀窍,所以我确实选择了另一种解决方案。我构建了一个服务,该服务会在每次路由更改时挂钩,并使用内置的 $anchorScroll 服务滚动到顶部。为我工作:-)。

              服务:

               (function() {
                  "use strict";
              
                  angular
                      .module("mymodule")
                      .factory("pageSwitch", pageSwitch);
              
                  pageSwitch.$inject = ["$rootScope", "$anchorScroll"];
              
                  function pageSwitch($rootScope, $anchorScroll) {
                      var registerListener = _.once(function() {
                          $rootScope.$on("$locationChangeSuccess", scrollToTop);
                      });
              
                      return {
                          registerListener: registerListener
                      };
              
                      function scrollToTop() {
                          $anchorScroll();
                      }
                  }
              }());
              

              注册:

              angular.module("mymodule").run(["pageSwitch", function (pageSwitch) {
                  pageSwitch.registerListener();
              }]);
              

              【讨论】:

                【解决方案14】:

                只要把这段代码运行起来

                $rootScope.$on("$routeChangeSuccess", function (event, currentRoute, previousRoute) {
                
                    window.scrollTo(0, 0);
                
                });
                

                【讨论】:

                • $window.scrollTop(0,0)对我来说比自动滚动更好。在我的情况下,我有进入和离开转换的视图。
                • 这对我来说也比 autoscroll="true" 更好用。由于某种原因,自动滚动为时已晚,它会在新视图已经可见后滚动到顶部。
                • 这对我来说效果最好: $rootScope.$on('$stateChangeSuccess',function(){ $("html, body").animate({ scrollTop: 0 }, 200); } );
                • $window.scrollTop 应该是 $window.scrollTo,否则它说它不存在。这个解决方案效果很好!
                • @JamesGentes 我也需要这个。谢谢。
                【解决方案15】:

                试试这个http://ionicframework.com/docs/api/service/$ionicScrollDelegate/

                它确实滚动到列表顶部 scrollTop()

                【讨论】:

                  【解决方案16】:

                  问题是您的 ngView 在加载新视图时会保留滚动位置。您可以指示$anchorScroll“在视图更新后滚动视口”(docs 有点模糊,但这里的滚动意味着滚动到新视图的顶部)。 p>

                  解决方案是将autoscroll="true"添加到您的ngView元素中:

                  <div class="ng-view" autoscroll="true"></div>
                  

                  【讨论】:

                  • 这对我有用,页面滚动到顶部,但我使用带有 smoothScroll 指令的scrollTo,有没有办法平滑滚动到顶部?另外你的解决方案滚动到视图顶部不是到页面有滚动到页面顶部吗?
                  • 文档状态如果属性设置为无值,则启用滚动。因此,您可以将代码缩短为 &lt;div class="ng-view" autoscroll&gt;&lt;/div&gt;,它的工作原理是一样的(除非您想让滚动有条件)。
                  • 它对我不起作用,文档没有说它会滚动到顶部
                  • 我发现如果自动滚动设置为 true,那么当用户“返回”时,他们会返回页面顶部,而不是返回页面顶部,这是不受欢迎的行为。
                  • 这会将您的视图滚动到此 div。因此,只有当它恰好位于页面顶部时,它才会滚动到页面顶部。否则你必须在 $stateChangeSuccess 事件监听器中运行$window.scrollTo(0,0)
                  【解决方案17】:

                  仅供遇到标题中描述的问题的任何人(就像我一样)也正在使用 AngularUI Router 插件...

                  正如在这个 SO question 中询问和回答的那样,当您更改路由时,angular-ui 路由器会跳转到页面底部。
                  Can't figure out why page loads at bottom? Angular UI-Router autoscroll Issue

                  但是,正如答案所述,您可以通过在您的 ui-view 上说 autoscroll="false" 来关闭此行为。

                  例如:

                  <div ui-view="pagecontent" autoscroll="false"></div>
                  <div ui-view="sidebar" autoscroll="false"></div> 
                  

                  http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.directive:ui-view

                  【讨论】:

                  • 我的不会跳到底部,它只是保留滚动位置而不是到顶部。
                  • 这不能回答问题。我遇到了同样的问题 - 当路线改变时,滚动级别只是停留在同一个地方,而不是滚动到顶部。我可以让它滚动到顶部,但只能通过更改哈希值,出于明显的原因我不想这样做。
                  【解决方案18】:

                  你可以使用这个javascript

                  $anchorScroll()
                  

                  【讨论】:

                  • 嗯,在 angularjs 中没那么简单。您的解决方案仅在 jquery 中有效。我正在寻找的是一种 优雅 在 angularjs 中执行此操作的方法
                  • 您是否尝试过使用 $anchorScroll(),它记录在 docs.angularjs.org/api/ng.%24anchorScroll
                  • 仅供参考如果您在$anchorScroll() 之前使用$location.hash('top') 指定位置,默认的前进/后退浏览器按钮将不再起作用;他们不断将您重定向到 URL 中的哈希
                  猜你喜欢
                  • 2017-02-17
                  • 2015-10-25
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-12-22
                  • 2021-12-15
                  • 2018-10-31
                  • 2020-08-08
                  相关资源
                  最近更新 更多