
Vue.jsでSEO対策した無限スクロール(Infinite Scroll)を実現する
2020.08.09
目次
「Vue.js」で無限スクロールする方法とは?
「無限スクロール(Infinite Scroll)」は、ページを切り替えることなくページネーションするテクニックです。
ページの一番下までスクロールすると、表示するコンテンツがなくなるまで、続きを自動的に読み込んでくれます。
スクロール操作が基本のモバイル端末で、「最もスマートなページネーション」とも言われています。
今回は、人気の「Vue.js」で無限スクロールを実装する方法と、無限スクロールに必要な SEO対策について解説していきます。
こちらの記事もオススメ!
無限スクロールの実装パターンと SEO 対策
無限スクロールには、2つの実装パターンがあります。
- 同一URLで、ページ内にコンテンツを読み込ませる方法
- 読み込むコンテンツ単位にURLを割り当ててページを分割する方法
それぞれの実装パターンを、SEOの観点で見ると次のような特徴があります。
1.同一URLで、ページ内にコンテンツを読み込ませる
この方法のメリットは、実装がシンプルで楽なことです。
しかし、この方法は、SEO 的には NG な実装パターンです。
なぜなら、検索エンジンの bot は、スクロールなしで見える情報しか認識できないからです。
また、この仕様は、ユーザービリティ的にも良くありません。
ページを訪れるたびに、毎回下までスクロールするのは面倒ですよね。
2.読み込むコンテンツ単位にURLを割り当ててページを分割
スクロールで読み込むコンテンツの単位(ページ単位)に、URLを割り当てる方法です。
これが、SEO的にも良いと言われている実装パターンです。
実装パターン実際どうやるの?
下記の画像を見てください。
「全部で40件のコンテンツを、20件ずつページ分けして表示する」と仮定します。
まず、コンテンツ20件ごとにURLを割り当てます。
そして、スクロールでページが切り替わるタイミングで「History API」の pushState() や replaceState()を使って、URLを書き換えます。

ページごとに URL を割り当てるメリット
ページ毎にURLを割り当てることで、検索エンジンのクローラーが情報を全てインデックスできるのです。
「同一URLでページ内にコンテンツを読み込ませる方法」に比べ、実装が複雑なのが難点ですが…。
無限スクロールを実装するなら、SEO 対策してあるこちらのパターンを使いましょう。
Vue.js で無限スクロールを実現する方法
Vue.js には、標準で無限スクロールを実現する機能がありません。
そのため、以下のどちらかの方法で、SEO 対策済みの無限スクロールを Vue.js で実装しましょう。
- 外部のライブラリを使う
- 自前で無限スクロールを実装する
注意
ただし、外部のライブラリを使う場合でも、一部の処理は自前で実装しなければなりません。
SEO 対策済みの無限スクロールライブラリが、公開されていないからです。
今回の方針
今回は、無限スクロールを「vue-infinite-loading」という外部のライブラリを使って実現します。
そして、SEO 対策の為の URL 切り替えを、「History API」を使って自前で実装していきます。
実装前の準備
事前準備として、新しいプロジェクトを用意しておきましょう。
npm、 vue-cliなど、Vue を開発するための環境が揃っている前提で話を進めます。
新しいプロジェクトを作る
まず、 vue-cliで、新しいプロジェクトを作成します。
今回は、「sample-inifnite-scroll」という名前にしました。
1 | vue create sample-inifnite-scroll |
vue-infinite-loading をインストール
プロジェクトが作成されたら、次に「vue-infinite-loading」をインストールします。
以下のいずれかの方法で、インストールしてください。
npm の場合
1 | npm install vue-infinite-loading -save |
yarn の場合
1 | yarn add vue-infinite-loading |
CDN 経由で使用する場合は、以下のタグを html に追加します。
1 | <script src="https://unpkg.com/vue-infinite-loading@^2/dist/vue-infinite-loading.js"></script> |
【Vue-infinite-loading】
https://peachscript.github.io/vue-infinite-loading/
これで、プロジェクトの準備ができました。
Vue.js で SEO 対策をした無限スクロールを実装
それでは、さっそく Vue.js で無限スクロールを実装していきましょう。
App.vueを開き、次の通りに編集してください。
Template
1 2 3 4 5 6 7 8 9 10 11 12 13 | <template> <div id="app"> <!--リストを表示する部分--> <ul class="list"> <li class="item" v-for="(item, index) in this.items" :key="index">{{item}}</li> </ul> <!--下スクロールした時に、次のページのデータを取得する無限スクロールコンポーネント--> <infinite-loading v-if="hasNext" @infinite="infiniteHandler" spinner="spiral" direction="bottom"> <div slot="no-more">No more</div> <!--これ以上表示するデータがない時に表示されるメッセージ--> <div slot="no-results">No results</div> <!--検索結果がない時に表示されるメッセージ--> </infinite-loading> </div> </template> |
テンプレートには、「検索したデータを表示する為のリスト部分」と、「無限スクロールを実現するための infinite-loadingタグ」を置きます。
infinite-loadting の役割
infinite-loadingは、ページの下の方までスクロールすると、 @infiniteイベントを発生させます。
そして、イベントハンドラの infiniteHandler関数の中で、次のページに表示するデータを検索してくれます。
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | import InfiniteLoading from 'vue-infinite-loading' export default { name: 'App', components: { InfiniteLoading }, data() { return { items: [], // リストに表示するデータ startPage: 0, // 開始ページ番号 endPage: 0, // 終了ページ番号 totalPages: 0, // 総ページ数 pageSize: 20, // 1ページに表示するデータ件数 initialized: false // 初回データアクセスが完了した後にtrueを設定するフラグ } }, computed: { hasNext() { return this.initialized && this.totalPages > this.endPage } }, mounted() { // 現在表示中のページ番号をURLに設定する為に、スクロールイベントを監視 window.addEventListener("scroll", () => this.scroll()) const urlParams = new URLSearchParams(window.location.search); const page = urlParams.get('page'); if (page) { // URLパラメータでページ番号が指定された場合、指定ページから表示 this.startPage = parseInt(page, 10) this.endPage = parseInt(page, 10) } else { // ページ番号の指定がない場合は1ページ目から表示 this.startPage = 1 this.endPage = 1 } // 初回データアクセス this.getItems(null, this.startPage, false) }, methods: { // スクロール時に、次ページに表示するデータを取得する処理 infiniteHandler($state) { if (this.endPage >= this.totalPages) { // 表示するデータが無くなったら$state.complete()を呼ぶ $state.complete() } else { // 表示するデータがある場合、時ページのデータを読み込む this.getItems($state, this.endPage + 1, true) } }, // ページに表示するデータを検索する処理 getItems($state, page, next) { setTimeout(() => { // 読込データを設定(実際はaxiosなどで非同期でデータを取得する想定) let data = [] for (let i = 1 ; i <= this.pageSize; i++) { data.push(`item${page}-${i}`) } // 総ページ数を設定(これも実際はaxiosなどで非同期でデータを取得する想定) this.totalPages = 10 // 現在表示しているデータの末尾に取得したデータを追加 this.items = this.items.concat(data) this.endPage = page // $state.loaded()でデータの読込完了を通知する if ($state) $state.loaded() this.$nextTick(() => { this.initialized = true }) }, 1000) }, // スクロールイベント発生時の処理 scroll() { // 現在のスクロールY座標から、画面に表示されているページ番号を計算する let scroll_pos = window.pageYOffset || document.documentElement.scrollTop let window_height = window.outerHeight let page = Math.ceil((scroll_pos + 0.5 * window_height) / 40 / this.pageSize) + (this.startPage - 1) // replaceStateでurlを書き換え(urlパラメータにページ番号を設定) window.history.replaceState(null, null, "/?page=" + page) } } } |
少し長いコードですが、概ね次のような処理をしています。
mounted()
mounted()は、ページロード時に呼ばれます。
URLパラメータで指定されたページ番号のデータを表示します。
ページ番号の指定がなければ、1ページ目が表示されます。
infiniteHandler
infiniteHandlerは、次のページのデータが必要になった時に呼ばれます。
次ページのデータを読み込んだ後、リストの末尾にデータを追加します。
$state.loaded() と $state.completed()
データを読み込む際、次のページに表示するデータが存在する場合は、 $state.loaded()が呼ばれます。
これ以上表示データがない場合(最終ページ)は、 $state.completed()を呼びます。
scroll 関数
scroll関数は、ブラウザでスクロールが発生すると呼ばれます。
現在のスクロール位置(Y座標)から表示中のページ番号を計算します。
そして、「History API」の replaceState()でURLパラメータに現在のページ番号をセットします。
CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 | .list { list-style: none; margin: 0; padding: 0; } .list li { height: 40px; border-top: solid 1px #ccc; border-bottom: solid 1px #777; box-sizing: border-box; margin: 0; padding: 0; } |
無限スクロールを実行
ここまで出来たら、実際に動きを確認してみましょう!
ターミナル上で、次のコマンドを入力します。
1 | npm run serve |
1ページ目
ブラウザで http://localhost:8080にアクセスしてみてください。
1ページ目の情報がリストになった状態で、ページが表示されていると思います。

では、下にスクロールして、無限スクロールが働いているか確認しましょう。
2ページ目
次の画像のように、下スクロールでローディングアイコンが表示された後、2ページ目の情報が表示されればOKです。

さらにスクロールを続けていきます。
2ページ目の情報が中盤あたりにくると、「History API」の replaceState()の処理により、URLパラメータにページ番号がセットされています。

URL にページ番号を指定する
また、URLにページ番号を直接指定すると、指定したページ番号のページからリストが表示されます。

さいごに
今回は、Vue.js でSEO対策した無限スクロールを実現する方法を紹介しました。
無限スクロールは、スマホ用サイトなどで、便利にページネーションする為のテクニックです。
検索エンジンのクローラーがインデックスしやすいように、SEO 対策もしっかりしておきましょう。
Vue.jsでのシステム開発依頼・お見積もりはこちらまでお願いします。
また、Vue.jsが扱えるエンジニアを積極採用中です!詳しくはこちらをご覧ください。
こちらの記事もオススメ!
ライトコードよりお知らせ






一緒に働いてくれる仲間を募集しております!
ライトコードでは、仲間を募集しております!
当社のモットーは「好きなことを仕事にするエンジニア集団」「エンジニアによるエンジニアのための会社」。エンジニアであるあなたの「やってみたいこと」を全力で応援する会社です。
また、ライトコードは現在、急成長中!だからこそ、あなたにお任せしたいやりがいのあるお仕事は沢山あります。「コアメンバー」として活躍してくれる、あなたからのご応募をお待ちしております!
なお、ご応募の前に、「話しだけ聞いてみたい」「社内の雰囲気を知りたい」という方はこちらをご覧ください。
ライトコードでは一緒に働いていただける方を募集しております!
採用情報はこちら書いた人はこんな人

IT技術2021.04.23【第2回】Djangoで日記アプリを作ろう~トップ画面編~
IT技術2021.04.16【第1回】Djangoで日記アプリを作ろう~環境構築編~
IT技術2021.03.2910月20日メジャーアップデート!「Node.js v15」の新機能とは?
IT技術2021.03.02TypeScriptの型を問題形式で学べる「type-challenges」とは?