更改路线不会在新页面中滚动到顶部

时间:2014-01-10 22:53:07

标签: javascript angularjs scroll angularjs-routing

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

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

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

18 个答案:

答案 0 :(得分:574)

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

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

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

答案 1 :(得分:44)

只需将此代码运行

即可
$rootScope.$on("$routeChangeSuccess", function (event, currentRoute, previousRoute) {

    window.scrollTo(0, 0);

});

答案 2 :(得分:35)

这段代码对我很有用..我希望它对你来说也很有用.. 所有你需要做的就是将$ anchorScroll注入你的运行块并将监听器函数应用到rootScope,就像我在下面的例子中所做的那样。

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

这是Angularjs模块的调用顺序:

  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)
  6. RUN BLOCK 在创建注入器后执行并用于kickstart应用程序..这意味着当您重定向到新的路由视图时,运行块中的侦听器调用

      

    $ anchorScroll()

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

答案 3 :(得分:31)

在尝试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');
})

答案 4 :(得分:18)

这是我(看似)强大,完整和(相当)简洁的解决方案。它使用缩小兼容样式(以及对模块的angular.module(NAME)访问权限。)

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

PS我发现autoscroll事件无论是设置为true还是false都没有效果。

答案 5 :(得分:15)

使用angularjs UI路由器,我正在做的是:

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

使用:

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

它永远不会在任何页面上失败,并且它不是全局的。

答案 6 :(得分:13)

对于任何遇到标题中描述的问题的人(正如我所做的那样)也在使用 AngularUI Router 插件......

正如在SO问题中所提出的那样,当你改变路线时,angular-ui路由器会跳到页面底部。
Can't figure out why page loads at bottom? Angular UI-Router autoscroll Issue

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

例如:

<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

答案 7 :(得分:7)

如果您使用ui-router,您可以使用(运行中)

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

答案 8 :(得分:7)

你可以使用这个javascript

$anchorScroll()

答案 9 :(得分:4)

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

var app = angular.module('hoofdModule', ['ngRoute']);

    app.controller('indexController', function ($scope, $window) {
        $scope.$on('$viewContentLoaded', function () {
            $window.scrollTo(0, 0);
        });
    });

答案 10 :(得分:3)

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

答案 11 :(得分:3)

派对有点晚了,但我已经尝试了所有可能的方法,但没有任何正常的方法。这是我优雅的解决方案:

我使用的控制器用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');
       });
    });
});

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

答案 12 :(得分:2)

上述所有答案都会破坏预期的浏览器行为。大多数人想要的东西是滚动到顶部的东西,如果它是一个新的&#34;页面,但如果你通过后退(或前进)按钮到达那里,则返回上一个位置。

如果您假设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,请使用上述技巧设置autoscroll="my_var"控制my_var的位置。但是我想大多数人都希望滚动整个页面,如果你要以#34; new&#34;那样滚动整个页面。

以上使用ui-router,但您可以使用ng-route而不是$routeChangeSuccess替换$stateChangeSuccess

答案 13 :(得分:2)

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

public void jsonParserArray(String json) {

        String [] resultsNumbers = new String[100];

        try {
            JSONObject jsonObjectGetData = new JSONObject(json);
            JSONObject jsonObjectGetNumbers = jsonObjectGetData.optJSONObject("results");
            JSONArray jsonArray = jsonObjectGetNumbers.getJSONArray("numbers");
            for (int i = 0; i < jsonArray.length(); i++) {
                resultsNumbers[i] = jsonArray.getString(i);
            }
        } catch (JSONException e) {
            e.printStackTrace();
            Log.e(LOG_TAG, e.toString());
        }
    }

我将其插入我的视图中,如下所示:

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

            })
        }
    };
}]);

答案 14 :(得分:2)

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

const routes: Routes = [

 {
   path: 'registration',
   loadChildren: () => RegistrationModule
},
];

 @NgModule({
  imports: [
   RouterModule.forRoot(routes,{scrollPositionRestoration:'enabled'})
  ],
 exports: [
 RouterModule
 ]
 })
  export class AppRoutingModule { }

答案 15 :(得分:0)

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

它会滚动到列表顶部scrollTop()

答案 16 :(得分:0)

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

我需要滚动到顶部,但想要某些过渡而不是

您可以逐个路线级别控制此 我将@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!
})

答案 17 :(得分:0)

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

{ "_id" : ObjectId("5b8abaaaaffeaa2b9c77b6b8"), "user_id" : "ddddddddd", "data" : [ { "_id" : ObjectId("5b8ab6e57ffe8b2b9c77b6b9"), "data1" : "qqqq", "fr" : "qqqq" }, { "_id" : ObjectId("5b8ab719406d7235240f4338"), "data1" : "III", "fr" : "III" } ] "__v" : NumberInt(0) }