1. ホーム
  2. アンギュラー

[解決済み】Angular 2 ルート変更時に上部にスクロールさせる

2022-03-24 21:08:05

質問

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

コンポーネントの ngInit でウィンドウをページトップにスクロールさせることはできますが、アプリ内のすべてのルートを自動的に処理できる、よりよい解決策はありますか?

解決方法は?

Angular 6.1 以降 :

Angular 6.1(2018-07-25リリース)では、"Router Scroll Position Restoration"という機能により、この問題を処理するための組み込みサポートが追加されました。公式で説明されているように アングラーブログ というように、ルーターの設定で有効にするだけです。

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

さらに、ブログには "将来のメジャーリリースでこれがデフォルトになることが期待される" と書かれています。今のところ(Angular 11.0時点では)そうなっていませんが、いずれはコードで何もする必要がなくなり、そのまま正しく動作するようになるでしょう。

この機能の詳細と、この動作をカスタマイズする方法については、以下のサイトを参照してください。 公式ドキュメント .

Angular 6.0およびそれ以前 :

GuilhermeMeireles さんの素晴らしい回答は、元の問題を修正する一方で、(ブラウザのボタンやコード内の位置情報を使って)戻る、進むに移動するときに期待される通常の動作を壊して、新しい問題を導入しています。期待される動作は、ページに戻るときに、リンクをクリックしたときと同じ位置までスクロールしたままになることですが、すべてのページに到着したときに一番上までスクロールすることは、明らかにこの期待を裏切るものです。

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

しかし、@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);
            }
        });
    }
}