概要
Angular で画面スクロールを実現する方法(いわゆる、画面内アンカーにジャンプする動き)
静的 HTML コンテンツにおいて、画面内スクロールはよく使われる機能だが、Angular はブラウザが要素を探すタイミングが Router によるコンポーネント生成より早いためうまくいかなかった。
スクロールを無理やり実現しようと思ったら、ディレクティブとか頑張ってイジったり、別ライブラリ入れたりと苦労する。
しかし、v6.1 から導入された Router Scroller という機能でスクロールが超簡単に実現できるようになったため、その実装方法の備忘録。
ただし、ヌルヌルっと動くようなアニメーション動作の実装は説明していない。あくまで目的の位置をパッと表示するスクロール処理に関する内容となっている。
前提条件
- Angular バージョン 6.1.0 以降のみ対応
- RouterModule による画面ルーティングが実装済みであること
Router Scroller の基礎知識
Angular のマイナーバージョンアップで v6.1.0-beta.1 から導入されたスクロール関連機能。
実際には、内包される以下のモジュールを利用することで実現する。
Scroll Position Restoration
スクロール位置の記憶と復元を行う機能を提供する。
Router によるナビゲーションを行うたびに、その時点でのスクロール位置を記憶し、ブラウザバックした時などに遷移前のスクロール位置に復元する。
この復元処理は Router によってタイミングが制御されているため、前の画面のルーティング処理が終わったあとにスクロールが移動するため『先にスクロールが走ってしまい後からコンポーネントが描画されてしまい位置がずれる』ということはない。
Anchor Scrolling
URL に #hoge
のようなフラグメントがある場合、同値の id を持つ要素が静的 HTML ページ内にあれば、そこに自動でスクロールされる機能を提供する。
Router によるナビゲーションだけでなく、リロード(画面更新)でも同様にスクロールしてくれる。
Scroll Offset
オフセットを指定する機能を提供する。 ヘッダーが「fixed」や「sticky」の場合などに、スクロール位置をズラしたい場合に設定できる。
具体的には、RouterModule.forRoot メソッド内で設定するため、部品単位ではなく全体的な設定になる。
例えば、Anchor Scrolling で自動スクロールした時に、上部のヘッダーが sticky なので、y座標を 50px だけ少し下にズラして見栄えを整える、といったことが出来る。
手順
Router Scroller を使用可能にする
デフォルトでは無効になっているため、そもそも機能を使えるように有効化設定する必要がある。
既に有効化している場合は、手順省略可。
...
@NgModule({
// RouterModule.forRoot(routes) の第2引数に、以下のようにオプションを追加
imports: [RouterModule.forRoot(routes, {
scrollPositionRestoration: 'enabled', // enabled で有効化
anchorScrolling: 'enabled', // enabled で有効化
scrollOffset: [0, 50] // [x, y] 設定:オフセットを使用する場合のみ記載
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
Scroll Position Restoration の使い方
有効化の設定が完了した時点で、特にやることはない。
今まで通りアプリのナビゲーションでページ遷移等を行い、ブラウザバックを行えば、勝手に最後のスクロール位置で前画面に戻ってくれる。
Anchor Scrolling の使い方
特定のページの、特定の場所に、画面遷移後に自動スクロールさせたい場合
まず、遷移先に id を設定する
...
<div id="hoge">
この要素に飛んで来たい!!!
</div>
...
当然のことながら画面内において一意なので、他の要素の id とカブらないように注意。
フラグメント付き URL を発行する処理を書く
アンカータグにプロパティを指定
<!-- パス /foo#hoge に遷移する -->
<a routerLink="/foo" fragment="hoge">飛べ!!!</a>
HTML のプロパティではなく、メソッド内の処理として実装する場合は以下のように書く。
import { Router } from '@angular/router'; // 追加
...
export class TestComponent {
constructor (private router: Router) {} // 追加
// 何かの契機で呼ばれるメソッド
jumpToHoge () {
// パス /foo#hoge に遷移する
this.router.navigate(['foo'], {fragment: 'hoge'});
}
}
constructor (private router: Router) {}
あとは、a タグをクリックするか、JS処理を実行すれば、 id="hoge" がページ上部に来るように、画面遷移およびスクロールを勝手にやってくれる。
Scroll Offset の使い方
こちらも、ルーティング設定のオプションで設定が完了した時点で、特にやることはない。
Anchor Scrolling でフラグメント付き URL で遷移した時に、オフセットをしていないと、ブラウザの上部のギリギリにピッタリくっつくように文字が表示されると思うので、オフセットの Y 軸値を適当な数値にすれば少し縦にズレるのが確認できるので、各自で良い感じの余白ができるように数値を微調整してください。
以上で、スクロールの実装は完了。