Angular 2 ルート変更で一番上までスクロール 質問する

Angular 2 ルート変更で一番上までスクロール 質問する

私の Angular 2 アプリでは、ページを下にスクロールしてページの下部にあるリンクをクリックすると、ルートが変更されて次のページに移動しますが、ページの上部までスクロールしません。その結果、最初のページが長く、2 番目のページのコンテンツが少ない場合、2 番目のページにコンテンツが不足しているという印象を与えます。コンテンツは、ユーザーがページの上部までスクロールした場合にのみ表示されるためです。

コンポーネントの ngInit でウィンドウをページの上部までスクロールできますが、アプリ内のすべてのルートを自動的に処理できるより良いソリューションはありますか?

ベストアンサー1

Angular 6.1以降:

Angular 6.1(2018年7月25日リリース)では、「ルータースクロール位置復元」と呼ばれる機能を通じて、この問題に対処するための組み込みサポートが追加されました。公式のAngularブログ次のようにルーターの設定でこれを有効にするだけです。

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

さらに、ブログには「将来のメジャー リリースではこれがデフォルトになる予定です」と書かれています。今のところこれは実現していません (Angular 13.0 の時点では) が、最終的にはコードで何もする必要がなくなり、そのままで正しく動作するようになります。

この機能の詳細と動作のカスタマイズ方法については、公式ドキュメント

Angular 6.0以前:

@GuilhermeMeireles の優れた回答は元の問題を解決しますが、ブラウザ ボタンまたはコード内の場所を使用して、戻るまたは進むときに予想される通常の動作が崩れることで、新しい問題が生じます。予想される動作は、ページに戻ると、リンクをクリックしたときと同じ場所までスクロールダウンしたままになるはずですが、すべてのページに到達するたびに上部までスクロールすると、明らかにこの期待が崩れます。

以下のコードは、Location の PopStateEvent シーケンスをサブスクライブし、新しく到達したページがそのようなイベントの結果である場合は先頭へのスクロール ロジックをスキップすることで、この種のナビゲーションを検出するロジックを拡張します。

戻る前のページがビューポート全体をカバーするほど長い場合、スクロール位置は自動的に復元されますが、@JordanNelson が正しく指摘しているように、ページが短い場合は、元の y スクロール位置を追跡し、ページに戻ったときに明示的に復元する必要があります。更新されたバージョンのコードでは、常にスクロール位置を明示的に復元することで、このケースもカバーしています。

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

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

    private lastPoppedUrl: string;
    private yScrollStack: number[] = [];

    constructor(private router: Router, private location: Location) { }

    ngOnInit() {
        this.location.subscribe((ev:PopStateEvent) => {
            this.lastPoppedUrl = ev.url;
        });
        this.router.events.subscribe((ev:any) => {
            if (ev instanceof NavigationStart) {
                if (ev.url != this.lastPoppedUrl)
                    this.yScrollStack.push(window.scrollY);
            } else if (ev instanceof NavigationEnd) {
                if (ev.url == this.lastPoppedUrl) {
                    this.lastPoppedUrl = undefined;
                    window.scrollTo(0, this.yScrollStack.pop());
                } else
                    window.scrollTo(0, 0);
            }
        });
    }
}

おすすめ記事