最近あまり見かけなくなった無限スクロールアニメーションをVue.js
とIntersectionObserve
を使用して実装してみました。メモ程度に残しておきます。
※Vue.jsで無限スクロールを実装する場合にはv-infinite-scrollというコンポーネントも用意されていますが、今回はオリジナルで作成しています。
実装例
下記が実装例です。
VueとIntersectionObserverで実装した無限スクロールスクロールに応じてブログの記事の取得と表示を繰り返しているシンプルな実装です。ブログの記事の取得にはWordPressのREST APIを使用しています。実装したかった機能は以下の通りです。
- 初回ロード時は10件の記事を表示
- スクロールすると追加で10件の記事を表示
- フェードアニメーションで追加の記事を表示
- データ取得時にローディングアニメーションを表示
GitHub
vue-infinite-scroll
コードの全体像
以下がコードの全体像です。無限スクロールと関係のないスタイルは省略しています。
処理の言語化
Vue.jsの基本的な機能の他にデータの取得にはaxios
、スクロールの監視にIntersectionObserver
を使用しています。要点となる処理ごとに忘れない程度にアウトプットします。
データの取得
axios
でのデータ取得時にパラメーターを指定しています。
WordPressのREST APIのレスポンスではoffset
で「投稿を取得したい任意のオフセット(何件目から取得するか)」を、per_page
で「1回のリクエストで返すレコードの数」を指定することができます。
今回は既に取得済みのデータ数からデータを取得したいのでoffsetにはposts.value.length
を、10件取得したいのでper_pageには10
を指定しました。
※パラメーター名はAPIの種類によって変わるので注意が必要。例えばJSONPlaceholderではそれぞれ_start
と_limit
が該当する。
DOMの更新を待機
リアクティブな値に新しく取得したデータを追加した後、再び要素を監視するためにnextTick()
を使用しています。
nextTick()
を使用することで、データ更新後にDOMへの反映を待ってから後続の処理を実行することができます。これはVueがリアクティブな状態を変更したとき、その結果実行されるDOMの更新は同期的には処理されないためです。
後続のobserveLastItem()
ではテンプレートのDOMを直接参照しているので、新しく取得したデータがDOMに追加された後に実行する必要があります。
テンプレートの要素を参照
useTemplateRef()
を使用して、テンプレートの要素を参照しています。
取得したいtemplate内の要素にref属性を設定し、設定した値をuseTemplateRef
に引数として渡すことで要素を取得することができます。
Vueの3.5以降のバージョンで使用できる比較的新しい機能のようです。
トランジションを設定
スクロールして追加の投稿が表示される際にフェードアニメーションを設定しています。
v-forでの追加の要素のレンダリング時にアニメーションを実行するために、TransitionGroup
を使用しています。nameはfadeで設定し、opacity
がゆっくり変化するようにしています。
このTransitionGroup
やTransition
コンポーネントがVueではとても便利だなと感じます。同じことをバニラJSでしようとすると、setTimeoutなどを使用する必要がありどうしてもコードが長くなってしまいがちです。
データの取得状況を監視
スクロール時に追加のデータが表示されるまでローディングを表示しています。
リアクティブなデータであるisLoading
をデータ取得時にはtrue
にすることにより、ローダーを条件付きレンダリングしています。
まとめ
今回はVue.jsで無限スクロールを実装する方法についてアウトプットしました。
Vueで無限スクロールを実装する方法は調べてみると他にも色々あるようで、Vuetifyのv-intersect
という機能を使用する方法もあるようです。
今回の実装を通じて非同期処理や、パラメーターを使用したデータの取得方法、トランジションなどの理解を深めることができました。Vueの理解度も0.5くらい上がった気がします。
参考サイト