Vue.jsでSEO対策した無限スクロール(Infinite Scroll)を実現する
IT技術
「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」という名前にしました。
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ページ目の情報がリストになった状態で、ページが表示されていると思います。
では、下にスクロールして、無限スクロールが働いているか確認しましょう。
2ページ目
次の画像のように、下スクロールでローディングアイコンが表示された後、2ページ目の情報が表示されればOKです。
さらにスクロールを続けていきます。
2ページ目の情報が中盤あたりにくると、「History API」のreplaceState()の処理により、URLパラメータにページ番号がセットされています。
URL にページ番号を指定する
また、URLにページ番号を直接指定すると、指定したページ番号のページからリストが表示されます。
さいごに
今回は、Vue.js でSEO対策した無限スクロールを実現する方法を紹介しました。
無限スクロールは、スマホ用サイトなどで、便利にページネーションする為のテクニックです。
検索エンジンのクローラーがインデックスしやすいように、SEO 対策もしっかりしておきましょう。
こちらの記事もオススメ!
2020.08.07JavaScript 特集知識編JavaScriptを使ってできることをわかりやすく解説!JavaScriptの歴史【紆余曲折を経たプログラミン...
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪、名古屋の4拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit