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

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


当前回答

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

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或指令的帮助下,允许你选择何时何地滚动顶部;

其他回答

这段代码背后的主要思想是将所有访问过的url和各自的scrollY数据保存在一个数组中。每当用户放弃一个页面(NavigationStart),这个数组就会被更新。每当用户进入一个新页面(NavigationEnd)时,我们决定是否恢复Y位置,这取决于我们如何到达这个页面。如果使用了某个页面上的引用,则滚动到0。如果使用浏览器后退/前进特性,则滚动到保存在数组中的Y。对不起,我的英语不好:)

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Location, PopStateEvent } from '@angular/common';
import { Router, Route, RouterLink, NavigationStart, NavigationEnd, 
    RouterEvent } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'my-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {

  private _subscription: Subscription;
  private _scrollHistory: { url: string, y: number }[] = [];
  private _useHistory = false;

  constructor(
    private _router: Router,
    private _location: Location) {
  }

  public ngOnInit() {

    this._subscription = this._router.events.subscribe((event: any) => 
    {
      if (event instanceof NavigationStart) {
        const currentUrl = (this._location.path() !== '') 
           this._location.path() : '/';
        const item = this._scrollHistory.find(x => x.url === currentUrl);
        if (item) {
          item.y = window.scrollY;
        } else {
          this._scrollHistory.push({ url: currentUrl, y: window.scrollY });
        }
        return;
      }
      if (event instanceof NavigationEnd) {
        if (this._useHistory) {
          this._useHistory = false;
          window.scrollTo(0, this._scrollHistory.find(x => x.url === 
          event.url).y);
        } else {
          window.scrollTo(0, 0);
        }
      }
    });

    this._subscription.add(this._location.subscribe((event: PopStateEvent) 
      => { this._useHistory = true;
    }));
  }

  public ngOnDestroy(): void {
    this._subscription.unsubscribe();
  }
}

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

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

如果你只是需要滚动页面到顶部,你可以这样做(不是最好的解决方案,但很快)

document.getElementById('elementId').scrollTop = 0;

如果你用相同的路径加载不同的组件,那么你可以使用ViewportScroller来实现同样的事情。

import { ViewportScroller } from '@angular/common';

constructor(private viewportScroller: ViewportScroller) {}

this.viewportScroller.scrollToPosition([0, 0]);

除了@Guilherme Meireles提供的完美答案, 您可以通过添加平滑滚动来调整实现,如下所示

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

然后添加下面的代码片段

 html {
      scroll-behavior: smooth;
    }

到你的样式。css