余白

https://blog.lacolaco.net/ に移転しました

Angular v6.1で導入されるRouter Scrollerの紹介

こんにちは、lacoです。

Angularの次のマイナーアップデートで、久しぶりに新機能らしい新機能が増えます。 その名もRouter Scrollerです。 長くAngularを使っている人には涙が出るほど嬉しい待望の機能です。 この記事ではRouter Scrollerの紹介と、来週のbeta.1まで待てない!今すぐ試してみたい!という奇特な方のために、最新のビルドで試す方法も紹介します。

Router Scroller

Router Scrollerは、Angular Routerにスクロールに関連する機能を与えるものです。 Router Scrollerを使うと、次のようなことができます。

  • ブラウザバックしたときに遷移前のスクロール位置に復元する
  • #foo のようなフラグメント付きのURLで、対応するIDを持つ要素まで自動でスクロールする

どちらも、静的なHTMLページであればブラウザが自動的に行なってくれるものですが、Angular RouterによるSPAでも同じふるまいを簡単に導入できます。 それぞれについて紹介します。

Scroll Position Restoration

Router Scroller第一の機能は、スクロール位置の記憶と復元です。 Routerによるナビゲーションを行うたびに、その時点でのスクロール位置を記憶します。 そして、ブラウザの戻る操作で前の画面に遷移したときには、記憶したスクロール位置に自動的に復元します。 この復元処理はRouterによってタイミングが制御されているため、前の画面のルーティング処理が終わったあとにスクロールが移動します。 よって、先にスクロールが走ってしまい、あとからコンポーネントが描画されてしまい位置がずれる、ということはありません。

https://media.giphy.com/media/g0EEPgQPgyKDoAO6fh/giphy.gif

Anchor Scrolling

もうひとつの機能は、URLに#fooのようなフラグメントが付いている場合、対応するIDを持つ要素があればそこまでスクロールする機能です。 これも静的なHTMLページではよく使われている機能ですが、Angularではブラウザが要素を探すタイミングがRouterによるコンポーネント生成より早いためうまくいきませんでした。 今回RouterがAnchor Scrolling機能を持ったことで、Angularアプリケーションであっても#fooによるスクロールが可能になりました。 Routerによるナビゲーションだけでなく、リロードしても同様にスクロールしてくれます。

https://media.giphy.com/media/2WH6rWL48nbrLScyMM/giphy.gif

使い方

Scroll Position RestorationもAnchor Scrollingも、v6.1.0時点ではデフォルトで無効になっています。 そのため、有効にするにはRouterModuleに設定を行う必要があります。

RouterModule.forRootメソッドの第2引数のオプションに、scrollPositionRestorationanchorScrolling が追加されています。 それぞれ、'enabled'に設定すると機能が有効になります。これだけで完了です。

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

Scroll Offset

Router Scrollerには、オフセットを指定することもできます。 ヘッダーがfixedやstickyな場合など、スクロール位置をずらしたい場合には、RouterModule.forRootメソッドの第2引数のオプションでscrollOffsetを設定します。 先程のAnchor Scrollingの例では、上部のヘッダーがstickyなので、y座標を64pxだけ下にずらしています。

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'enabled',
      anchorScrolling: 'enabled',
      scrollOffset: [0, 64] // [x, y]
    })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule {}

今すぐ試すには

Router Scrollerはv6.1.0-beta.1からリリースに含められる予定です。 それより先に試したい方は、@angular/router@angular/common@angular/platform-browser@angular/platform-browser-dynamicの4つをパッケージを開発版ビルドに置き換える必要があります。次のようなバージョン指定でよいでしょう。

    "@angular/common": "angular/common-builds",
    "@angular/compiler": "^6.0.0",
    "@angular/core": "^6.0.0",
    "@angular/platform-browser": "angular/platform-browser-builds",
    "@angular/platform-browser-dynamic": "angular/platform-browser-dynamic-builds",
    "@angular/router": "angular/router-builds",

もっと知りたい

さらに詳しく知りたい方は、当該機能のコミット内容を読むと良いでしょう。

github.com

この記事のサンプルコードはGitHubで公開しています。

github.com