更改路由不会滚动到新页面的顶部

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

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

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

103747 次浏览

你可以使用这个javascript

$anchorScroll()

供任何遇到标题中描述的问题的人参考(就像我一样),谁也在使用 AngularUI Router plugin…

. AngularUI Router plugin

在这个SO问题中,当你改变路由时,angular-ui路由器会跳到页面的底部 不能't弄清楚为什么页面加载底部?Angular UI-Router自动滚动问题 < / p >

然而,正如答案所述,你可以通过在你的ui-view上说autoscroll="false"来关闭这个行为。

例如:

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

< a href = " http://angular-ui.github.io/ui-router/site/ / api / ui.router.state。指令:ui-view" rel="nofollow noreferrer">http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.directive:ui-view

问题是你的ngView在加载一个新视图时保持滚动位置。你可以指示$anchorScroll“在视图更新后滚动视口”(文档有点模糊,但这里的滚动意味着新视图的滚动到顶部)。

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

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

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

它会滚动到列表的顶部

只需要运行这段代码

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


window.scrollTo(0, 0);


});

将自动滚动设置为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();
}]);

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

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

PS我发现自动滚动的东西没有影响,无论是设置为真或假。

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

如果你采用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。但我认为大多数人会想滚动整个页面,如果你去“新的”页面。

上面使用ui-router,不过你可以使用ng-route来代替,把$routeChangeSuccess换成__abc1。

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

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

:

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

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

在尝试了一两个小时的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');
})

如果你使用ui-router,你可以使用(on run)

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

我找到了这个解。如果你转到一个新视图,函数就会被执行。

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


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

有点晚了,但我已经尝试了所有可能的方法,没有一个能正常工作。以下是我的优雅解决方案:

我使用一个控制器来管理我所有的页面与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');
});
});
});

所有可能的方法我都试过了,这个方法效果最好。

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

 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)

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

$ anchorScroll ()

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

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

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>

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

我需要滚动到顶部,但需要有些过渡不是

可以在路由级别上控制 我通过@wkonkel组合了上述解决方案,并在一些路由声明中添加了一个简单的noScroll: true参数。然后我在转换的时候抓住了它。< / p >

总而言之:它在新转换时浮动到页面顶部,在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块中,并注入$statemyApp.run(function($state){...})

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

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

这为我工作,包括自动滚动

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

简单方法:在主路模块enabled中添加scrollPositionRestoration 这样的:< / p >

const routes: Routes = [


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


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