![広告メディア事業部](/_next/image?url=https%3A%2F%2Fapi.rightcode.co.jp%2Fwp-content%2Fuploads%2F2022%2F08%2Fcropped-icon_tobaru_2_150150-150x150.png&w=64&q=75)
Vue.jsでSEO対策した無限スクロール(Infinite Scroll)を実現する
![広告メディア事業部](/_next/image?url=https%3A%2F%2Fapi.rightcode.co.jp%2Fwp-content%2Fuploads%2F2022%2F08%2Fcropped-icon_tobaru_2_150150-150x150.png&w=64&q=75)
IT技術
![](/_next/image?url=https%3A%2F%2Fapi.rightcode.co.jp%2Fwp-content%2Fuploads%2F2020%2F06%2Fseo.png&w=3840&q=75)
「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を書き換えます。
![](https://api.rightcode.co.jp/wp-content/uploads/2020/06/vue-js-seo-infinite-scroll_01.png)
ページごとに 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」という名前にしました。
1vue create sample-inifnite-scroll
vue-infinite-loading をインストール
プロジェクトが作成されたら、次に「vue-infinite-loading」をインストールします。
以下のいずれかの方法で、インストールしてください。
npm の場合
1npm install vue-infinite-loading -save
yarn の場合
1yarn 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<template>
2 <div id="app">
3 <!--リストを表示する部分-->
4 <ul class="list">
5 <li class="item" v-for="(item, index) in this.items" :key="index">{{item}}</li>
6 </ul>
7 <!--下スクロールした時に、次のページのデータを取得する無限スクロールコンポーネント-->
8 <infinite-loading v-if="hasNext" @infinite="infiniteHandler" spinner="spiral" direction="bottom">
9 <div slot="no-more">No more</div> <!--これ以上表示するデータがない時に表示されるメッセージ-->
10 <div slot="no-results">No results</div> <!--検索結果がない時に表示されるメッセージ-->
11 </infinite-loading>
12 </div>
13</template>
テンプレートには、「検索したデータを表示する為のリスト部分」と、「無限スクロールを実現するためのinfinite-loadingタグ」を置きます。
infinite-loadting の役割
infinite-loadingは、ページの下の方までスクロールすると、@infiniteイベントを発生させます。
そして、イベントハンドラのinfiniteHandler関数の中で、次のページに表示するデータを検索してくれます。
JavaScript
1import InfiniteLoading from 'vue-infinite-loading'
2
3export default {
4 name: 'App',
5 components: {
6 InfiniteLoading
7 },
8 data() {
9 return {
10 items: [], // リストに表示するデータ
11 startPage: 0, // 開始ページ番号
12 endPage: 0, // 終了ページ番号
13 totalPages: 0, // 総ページ数
14 pageSize: 20, // 1ページに表示するデータ件数
15 initialized: false // 初回データアクセスが完了した後にtrueを設定するフラグ
16 }
17 },
18 computed: {
19 hasNext() {
20 return this.initialized && this.totalPages > this.endPage
21 }
22 },
23 mounted() {
24
25 // 現在表示中のページ番号をURLに設定する為に、スクロールイベントを監視
26 window.addEventListener("scroll", () => this.scroll())
27
28 const urlParams = new URLSearchParams(window.location.search);
29 const page = urlParams.get('page');
30
31 if (page) {
32 // URLパラメータでページ番号が指定された場合、指定ページから表示
33 this.startPage = parseInt(page, 10)
34 this.endPage = parseInt(page, 10)
35 } else {
36 // ページ番号の指定がない場合は1ページ目から表示
37 this.startPage = 1
38 this.endPage = 1
39 }
40
41 // 初回データアクセス
42 this.getItems(null, this.startPage, false)
43 },
44 methods: {
45
46 // スクロール時に、次ページに表示するデータを取得する処理
47 infiniteHandler($state) {
48 if (this.endPage >= this.totalPages) {
49 // 表示するデータが無くなったら$state.complete()を呼ぶ
50 $state.complete()
51 } else {
52 // 表示するデータがある場合、時ページのデータを読み込む
53 this.getItems($state, this.endPage + 1, true)
54 }
55 },
56
57 // ページに表示するデータを検索する処理
58 getItems($state, page, next) {
59 setTimeout(() => {
60
61 // 読込データを設定(実際はaxiosなどで非同期でデータを取得する想定)
62 let data = []
63 for (let i = 1 ; i <= this.pageSize; i++) {
64 data.push(`item${page}-${i}`)
65 }
66 // 総ページ数を設定(これも実際はaxiosなどで非同期でデータを取得する想定)
67 this.totalPages = 10
68
69 // 現在表示しているデータの末尾に取得したデータを追加
70 this.items = this.items.concat(data)
71 this.endPage = page
72
73 // $state.loaded()でデータの読込完了を通知する
74 if ($state) $state.loaded()
75
76 this.$nextTick(() => {
77 this.initialized = true
78 })
79 }, 1000)
80 },
81
82 // スクロールイベント発生時の処理
83 scroll() {
84 // 現在のスクロールY座標から、画面に表示されているページ番号を計算する
85 let scroll_pos = window.pageYOffset || document.documentElement.scrollTop
86 let window_height = window.outerHeight
87 let page = Math.ceil((scroll_pos + 0.5 * window_height) / 40 / this.pageSize) + (this.startPage - 1)
88 // replaceStateでurlを書き換え(urlパラメータにページ番号を設定)
89 window.history.replaceState(null, null, "/?page=" + page)
90 }
91 }
92}
少し長いコードですが、概ね次のような処理をしています。
mounted()
mounted()は、ページロード時に呼ばれます。
URLパラメータで指定されたページ番号のデータを表示します。
ページ番号の指定がなければ、1ページ目が表示されます。
infiniteHandler
infiniteHandlerは、次のページのデータが必要になった時に呼ばれます。
次ページのデータを読み込んだ後、リストの末尾にデータを追加します。
$state.loaded() と $state.completed()
データを読み込む際、次のページに表示するデータが存在する場合は、$state.loaded()が呼ばれます。
これ以上表示データがない場合(最終ページ)は、$state.completed()を呼びます。
scroll 関数
scroll関数は、ブラウザでスクロールが発生すると呼ばれます。
現在のスクロール位置(Y座標)から表示中のページ番号を計算します。
そして、「History API」のreplaceState()でURLパラメータに現在のページ番号をセットします。
CSS
1.list {
2 list-style: none;
3 margin: 0;
4 padding: 0;
5}
6.list li {
7 height: 40px;
8 border-top: solid 1px #ccc;
9 border-bottom: solid 1px #777;
10 box-sizing: border-box;
11 margin: 0;
12 padding: 0;
13}
無限スクロールを実行
ここまで出来たら、実際に動きを確認してみましょう!
ターミナル上で、次のコマンドを入力します。
1npm run serve
1ページ目
ブラウザでhttp://localhost:8080にアクセスしてみてください。
1ページ目の情報がリストになった状態で、ページが表示されていると思います。
![](https://api.rightcode.co.jp/wp-content/uploads/2020/06/vue-js-seo-infinite-scroll_02.png)
では、下にスクロールして、無限スクロールが働いているか確認しましょう。
2ページ目
次の画像のように、下スクロールでローディングアイコンが表示された後、2ページ目の情報が表示されればOKです。
![](https://api.rightcode.co.jp/wp-content/uploads/2020/06/vue-js-seo-infinite-scroll_03.png)
さらにスクロールを続けていきます。
2ページ目の情報が中盤あたりにくると、「History API」のreplaceState()の処理により、URLパラメータにページ番号がセットされています。
![](https://api.rightcode.co.jp/wp-content/uploads/2020/06/vue-js-seo-infinite-scroll_04.png)
URL にページ番号を指定する
また、URLにページ番号を直接指定すると、指定したページ番号のページからリストが表示されます。
![](https://api.rightcode.co.jp/wp-content/uploads/2020/06/vue-js-seo-infinite-scroll_05.png)
さいごに
今回は、Vue.js でSEO対策した無限スクロールを実現する方法を紹介しました。
無限スクロールは、スマホ用サイトなどで、便利にページネーションする為のテクニックです。
検索エンジンのクローラーがインデックスしやすいように、SEO 対策もしっかりしておきましょう。
こちらの記事もオススメ!
2020.08.07JavaScript 特集知識編JavaScriptを使ってできることをわかりやすく解説!JavaScriptの歴史【紆余曲折を経たプログラミン...
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
![広告メディア事業部](/_next/image?url=https%3A%2F%2Fapi.rightcode.co.jp%2Fwp-content%2Fuploads%2F2022%2F08%2Fcropped-icon_tobaru_2_150150-150x150.png&w=3840&q=75)
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit