山崎屋の技術メモ

IT業界で働く中でテクノロジーを愛するSIerのシステムエンジニア👨‍💻 | AndroidとWebアプリの二刀流🧙‍♂️ | コードの裏にあるストーリーを綴るブログ執筆者✍️ | 日々進化するデジタル世界で学び続ける探究者🚀 | #TechLover #CodeArtisan、気になること、メモしておきたいことを書いていきます。

【Vue】無限スクロールライブラリを試す

Twitter や Facebook みたいにスクロールして下段まで行くと追加でデータをロードしてくれるあれを Vue を使って試したいと思います。

f:id:yyama1556:20181116160846g:plain
 
今回は Qiita の API を使用してデータを取得し、無限スクロールしていこうと思います。
 
 

使用ライブラリ

 
便利な無限スクロールライブラリがあるはずなので探してみました。
 
参考にしたサイト:
vuejsで無限ロードを実装 - Qiita
 
vue-infinite-scrollvue-infinite-loading というのがあるようです。
 
GitHub のスターの数は前者のほうが 1,800 位で後者のほうは 1,400 位。ただ、活発に活動しているのは後者。
 
先行となる vue-infinite-scroll のいい所も取り込んでいるだろうし、今回は後者の vue-infinite-loading を使ってみたいと思います。

公式サイト:
Vue-infinite-loading
 
 

プロジェクトの準備

vue プロジェクトの雛形作成

vue-cli を使用して雛形プロジェクトを準備します。やり方は次の記事を参考にしてください。
プロジェクト名は「inf-loding」としました。
www.shookuro.com
 

ライブラリのインストール

npm を使用してライブラリをインストールします 。
まずは、vue-infinite-loading。

npm install vue-infinite-loading -S


次に Ajax ライブラリの axios 。

npm install axios -S


 

ファイルの整理

vue ファイルは src/ 配下の App.vue のみ使用するので、src/components/ 配下の HelloWorld.vue は削除してしまいます。
 
  

コーディング

App.vue の編集

というか App.vue しか編集しません。

細かい編集内容は割愛。最後に App.vue の全量を掲載しておきます。

style の削除

見た目はショボくてもいいので、以下の <style> タグは削除してしまいましょう。

<style> /* タグごと全部消す */
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
script の編集

InfiniteLoading と axios を import します。

import InfiniteLoading from 'vue-infinite-loading'
import axios from 'axios'


Qiita 記事取得 API の URL を定数として保持します。

const api = 'https://qiita.com/api/v2/items'

 
components に IniniteLoading を登録します。これで <infinite-loading> カスタムタグが利用可能になります。

  components: {
    InfiniteLoading
  },


data には現在読み込み完了したページ番号( page )と、実際のデータ( list )を保持しておきます。

  data() {
    return {
      page: 1,
      list: [],
    }
  },

 
メソッドには追加読み込みのイベントが発生したときのハンドラを定義しておきます。InfiniteLoding が自動でイベントを発火しますので、開発者は呼び出しません。

  methods: {
    infiniteHandler($state) {


axios を使って API を呼び出します。headers の Authorization は Qiita で取得した個人用アクセストークンを設定します。

今回使用する API の場合、アクセストークンがなくてもいいのですがその場合、1 時間に 60 回しか API 呼び出しできません。XXX・・・の部分は自分のアクセストークンを指定してください。

      axios.get(api, {
        params: {
          page: this.page,
          per_page: 20
        },
        headers: {
          'Authorization' : 'Bearer ' + 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
        }
      }).then(({ data }) => {
        if (data.length) {
          this.page += 1
          this.list.push(...data)
          $state.loaded()
        } else {
          $state.complete()
        }
      }).catch((err) => {
          $state.complete()
      })

1 レコード以上読み込みできた場合は $state.loaded() を呼び出します。

1 レコードも読み込まれなかった場合は、これ以上データがないと判断し、$state.complete() を呼び出します。そうすると追加読み込みイベントが発火しなくなります。

今回は、エラーの場合も $state.complete() にしてしまっていますが、ここはシステムにより適切にハンドリングしましょう。

template の編集

table の tr タグに v-for を仕込んで保持しているデータの数だけループさせます。

<table>
  <tr v-for="(item, $index) in list" :key="$index">
    <td><a :href="item.url">{{item.title}}</a></td>
  </tr>
</table>


table の下に InfiniteLoding のカスタムタグを追加し、追加読み込みイベントのハンドラ ( infiniteHandler ) を指定します。

<infinite-loading @infinite="infiniteHandler"></infinite-loading>

このタグには InfiniteLogind で用意されているオプションも v-bind で指定できます。
 
オプションの一覧はこちら。
API | Vue-infinite-loading
 
例えば、どのくらい画面の下までスクロールしたら追加読み込みイベントを発火させるか調節する場合、distance プロパティを指定します。

デフォルトは 100 です。これを 1,000 にすると、ちょっと下にスクロールしただけで追加読み込みが発生します。 ( v-bind は : に省略可)

<infinite-loading @infinite="infiniteHandler" :distance="1000"></infinite-loading>

他にもスピナー(くるくる回るやつ)の種類や読み込むデータがないときに表示するメッセージなど設定できます。

 

完成

完成しました。
f:id:yyama1556:20181123145342g:plain
 

まとめ

Vue で、InfiniteLoding というライブラリと Qiita API を使用した無限スクロールの実装を行いました。

割と簡単に実装できます。Twitter や Facebook の クライアントを作成するときに使えそうです。

最後に App.vue の全量を貼っておきます。

<template>
<div>
<table>
  <tr v-for="(item, $index) in list" :key="$index">
    <td><a :href="item.url">{{item.title}}</a></td>
  </tr>
</table>
<infinite-loading @infinite="infiniteHandler"></infinite-loading>
</div>
</template>

<script>
import InfiniteLoading from 'vue-infinite-loading'
import axios from 'axios'

const api = 'https://qiita.com/api/v2/items'
export default {
  name: "app",
  components: {
    InfiniteLoading
  },
  data() {
    return {
      page: 1,
      list: [],
    }
  },
  methods: {
    infiniteHandler($state) {
      axios.get(api, {
        params: {
          page: this.page,
          per_page: 20
        },
        headers: {
          'Authorization' : 'Bearer ' + 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
        }
      }).then(({ data }) => {
        if (data.length) {
          this.page += 1
          this.list.push(...data)
          $state.loaded()
        } else {
          $state.complete()
        }
      }).catch((err) => {
          $state.complete()
      })
    }
  }
}
</script>

それでは!

Vue.js入門 基礎から実践アプリケーション開発まで

Vue.js入門 基礎から実践アプリケーション開発まで

  • 作者: 川口和也,喜多啓介,野田陽平,手島拓也,片山真也
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/09/22
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る
改訂新版 Vue.jsとFirebaseで作るミニWebサービス (技術書典シリーズ(NextPublishing))

改訂新版 Vue.jsとFirebaseで作るミニWebサービス (技術書典シリーズ(NextPublishing))

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js