在我的Angular 2应用中,当我向下滚动页面并单击页面底部的链接时,它确实会改变路由并将我带到下一页,但它不会滚动到页面顶部。因此,如果第一页很长,第二页内容很少,就会给人一种第二页缺乏内容的印象。因为只有当用户滚动到页面顶部时,内容才可见。

我可以滚动窗口到ngInit组件的页面顶部,但是,有没有更好的解决方案,可以自动处理我的应用程序中的所有路由?


当前回答

这个解决方案基于@FernandoEcheverria和@GuilhermeMeireles的解决方案,但它更简洁,并且可以使用Angular路由器提供的popstate机制。这允许存储和恢复多个连续导航的滚动级别。

我们将每个导航状态的滚动位置存储在一个地图scrollLevels中。一旦有了popstate事件,即将被恢复的状态ID就会由Angular路由器提供:event. restoredstate . navigationid。然后,这将用于从scrollLevels获取该状态的最后一个滚动级别。

如果路由没有存储滚动级别,它将滚动到顶部,正如您所期望的那样。

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class AppComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit() {
    const scrollLevels: { [navigationId: number]: number } = {};
    let lastId = 0;
    let restoredId: number;

    this.router.events.subscribe((event: Event) => {

      if (event instanceof NavigationStart) {
        scrollLevels[lastId] = window.scrollY;
        lastId = event.id;
        restoredId = event.restoredState ? event.restoredState.navigationId : undefined;
      }

      if (event instanceof NavigationEnd) {
        if (restoredId) {
          // Optional: Wrap a timeout around the next line to wait for
          // the component to finish loading
          window.scrollTo(0, scrollLevels[restoredId] || 0);
        } else {
          window.scrollTo(0, 0);
        }
      }

    });
  }

}

其他回答

您可以在主组件上注册路由更改侦听器,并在路由更改时滚动到顶部。

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {
    constructor(private router: Router) { }

    ngOnInit() {
        this.router.events.subscribe((evt) => {
            if (!(evt instanceof NavigationEnd)) {
                return;
            }
            window.scrollTo(0, 0)
        });
    }
}

你也可以在Route.ts中使用scrollOffset。 参考Router ExtraOptions

@NgModule({
  imports: [
    SomeModule.forRoot(
      SomeRouting,
      {
        scrollPositionRestoration: 'enabled',
        scrollOffset:[0,0]
      })],
  exports: [RouterModule]
})

对于每个正在寻找解决方案并阅读这篇文章的人。的

imports: [
  RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'
  }),
  ...
]

并没有回答这个主题的问题。如果我们查看Angular的源代码,我们会看到一些有趣的行:

这个东西只对反向导航有用。其中一个解决方案可能是:

constructor(router: Router) {

    router.events
        .pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd))
        .subscribe(() => {
            this.document.querySelector('#top').scrollIntoView();
        });
}

这将查看每个导航到该id的div并滚动到它;

另一种方法是使用相同的逻辑,但在decorator或指令的帮助下,允许你选择何时何地滚动顶部;

大家好,这在angular 4中是适用的。你只需要引用父节点来滚动路由器更改

layout.component.pug

.wrapper(#outlet="")
    router-outlet((activate)='routerActivate($event,outlet)')

layout.component.ts

 public routerActivate(event,outlet){
    outlet.scrollTop = 0;
 }`

对于iphone/ios safari,您可以使用setTimeout进行包装

setTimeout(function(){
    window.scrollTo(0, 1);
}, 0);