2019/05/20SHAREツイートシェアはてブGoogle+PocketLINEこんにちは、あかしぃです。スクロールスパイ機能つきの追従ヘッダーで、かつ、該当のセクションにスクロールしたときにナビのアイテムがフォーカスされる、という機能を作ったので、メモがてらに記事にしました。文章で見てもなんのこっちゃ?って感じだと思いますが、こちらのページを見るとイメージがつくかと(スマホで見るか、開発者モードでスマホのwidthにして見てください)。意外に似たようなライブラリがなかったので、Javascript(vue.js)でスクラッチな感じで書いています。currentIndexが更新されるたびに、navItemを移動させるまとめコードの全体像まず最初に、コード例を以下に記します。スクロールが行われるたびに、現在位置が各セクションの中かどうかを判定する。#f08000;}</style>上記が、スクロールスパイ機能を搭載したヘッダーナビコンポーネントです。このコンポーネントの設置イメージはこんな感じ。sticky;}</style>nav要素は直接dataに記述していますが、複数のページで使い回す場合は、サーバー側からnavItemsとして受け取り、propsで渡すようにすると再利用性が増すかなと思います。簡単にですが、各コードについて解説していきます。コードのコメント部分で、1、2、3、4とナンバリングしているのは、処理が行われる順番で、その通りに見ていくと理解しやすいかと思います。解説もその順番で進めます。スクロールイベントにscrollSpyメソッドを紐づけるスクロールスパイを実装するには、リアルタイムでスクロール位置を取得し、各処理を行う必要があります。そのために、addEventListenerでスクロールイベントにscrollSpyメソッドを紐づけています。スクロールイベントが発生するたびにメソッドを実行するのは高負荷なので、lodashライブラリのthrottleメソッドを使い、最短でも50ミリ秒に1回しかメソッドが実行されないようにしています。それぞれのnavItemの、画面左端からの位置をpositionsに格納しておく今回のキモは、ページの各セクション内にスクロールしたときに、一致するnavItemを左端にスクロール表示させることです。それを実現するために、getBoundingClientRect().leftで、それぞれのnavItemの最初のポジションを取得し、positionsに格納しておきます。あとは、スクロール位置が各セクションに移動したタイミングで、スクロールバーを一致するnavItemのところまでスクロールしてあげればいいわけですね。スクロールが行われるたびに、現在位置が各セクションの中であるかどうかを判定するscrollSpyメソッドは、スクロールが行われるたびに実行され、ページにおける現在位置が各セクションの中かどうかを判定するメソッドです。この例では、各セクションにはscroll-spyクラスが付与されているので、document.getElementsByClassNameを使って対象となるelementをまとめて取得しています。getElementsByClassNameは、elementが格納された配列を返すので、forEachでループを行い、各elementに対して判定、処理を実行します。elTop、elBottomは、画面端からのelementのtop位置とbottom位置です。ややこしいですが、getBoundingClientRectはページの頂点を基準にして距離を返すのではなく、今の表示位置からの相対的な距離を返します。elTopがマイナスの値で、かつelBottomよりプラスの値であれば、現在位置はそのセクション内(element内)である、ということになります。element内であれば、該当のnavItemにactiveクラスを付与しています。activeクラスは単純に色をつけるだけのクラスで、ちょうど今そのセクションを読んでいるよ、ということをユーザーに知らせるためのものです。最後に、currentIndexに現在のセクションindexを格納します。currentIndexが更新されるたびに、navItemを移動させるcurrentIndexの値が変わる=ユーザーが次のセクションに移動した、ということなので、この変化をキャッチしてnavItemを移動させます。Vueには値が更新されると実行されるwatchオプションがあるので、これを使います。やっていることは単純で、positionsにはnavItemごとの移動させるべきポジションが格納されているので、currentIndexで目的のポジションを参照し、その位置にスクロールさせているだけです。まとめ今回の例はスマホ特化のスクロールスパイなので、PCなどの大画面から見ると違和感バリバリの機能になる・・・と思います。参考サイトのように、大画面の場合は違った挙動をするヘッダーを実装する必要があります。smooth-scroll.jsといったライブラリを使えば、ほぼ修正なしでスムーススクロールも実装できます。activeクラスのcssを変更すれば、結構いろんなことができるので、そちらもぜひ試してみてくださいね。コメントをキャンセルメールアドレスが公開されることはありません。PostsVue.jsでフォーカス機能つきのスクロールスパイを実装するあかしぃ流、辛くない技術書の読み方Nuxt(Vue).jsで郵便番号が入力されたら自動的に住所も入力されるフォームを作るフロントエンド開発の副業を探しています。