Nuxt.jsとvue-infinite-loadingを使って無限スクロールを実装する

業務でvue-inifinite-loadingというプラグインを使う機会があったので、今回はNuxt.jsとvue-inifinite-loadingを使って無限スクロールを実装してみました。

# 事前準備
まずvue-inifinite-loadingのプラグインをインストールします。

```js
npm install vue-infinite-loading -S
or
yarn add vue-infinite-loading
```

次に`plugins/infiniteloading.js`に以下を追加します。

```plugin/infiniteloading.js
import Vue from 'vue'
import InfiniteLoading from 'vue-infinite-loading'

Vue.component('infinite-loading', InfiniteLoading)
```

最後に`nuxt.config.js`のpluginに先ほど作成したファイルを追記します。

```nuxt.config.js
plugins: [
  { src: '~/plugins/infiniteloading', ssr: false }
]
```

初期設定はこれで終わりです。

# 実際に使ってみる
### DEMO
今回作ったデモはこちらです。
簡単なデモですが、リストを作って一定数スクロールすると読み込み処理が走って、続きのリストが表示されるようになっています。
![infinitescroll.gif](https://qiita-image-store.s3.amazonaws.com/0/271450/56849dba-2c99-6d2e-d198-f5bb5344d45f.gif)

### コード
実際のコードはこちらです。

```components/InfiniteScroll.vue
<template>
  <div class="infinite-scroll">
    <ul class="infinite-scroll-list">
      <li class="infinite-scroll-list-item" v-for="i in this.count" :key="i">scroll {{ i }}</li>
    </ul>
    <infinite-loading 
      ref="infiniteLoading" 
      spinner="spiral"
      @infinite="infiniteHandler">
      <div slot="no-results"/>
    </infinite-loading>
  </div>
</template>

<script>
export default {
  name: 'InfiniteScroll',
  data() {
    return {
      count: 20
    }
  },
  methods: {
    infiniteHandler() {
      setTimeout(() => {
        this.count += 20
        this.$refs.infiniteLoading.stateChanger.loaded()
      }, 1000)
    }
  }
}
</script>

<style>
.infinite-scroll {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 680px;
  margin: 100px 0;
}

.infinite-scroll-list-item {
  height: 60px;
  margin: 10px 0;
  border-bottom: 1px solid #eaeaea;
  padding-bottom: 10px;
}
</style>
```

使用方法としては、templateに`infinite-loading`を使います。
`@infinite`には作ったmethod名を記入します。
今回はinfiniteHandlerというメソッド名にしています。

次にメソッド内の処理についてです。

```js
methods: {
  infiniteHandler() {
    setTimeout(() => {
      this.count += 20
      this.$refs.infiniteLoading.stateChanger.loaded()
    }, 1000)
  }
}
```

このメソッド内ではメソッドが読み込まれたらcount値を加算させ、`this.$refs.infiniteLoading.stateChanger.loaded()`の処理で再度ローディングの処理を行います。

##読み込むデータがない場合の処理
### DEMO
一定数スクロールをして、表示するデータがなくなった場合に`No more data :)`という文字が表示されるようになっています。
![infiniteloading_finish.gif](https://qiita-image-store.s3.amazonaws.com/0/271450/b8ff4c87-2da9-df28-ad02-88e7df587ace.gif)

### コード
```js
methods: {
  infiniteHandler() {
    setTimeout(() => {
      if (this.count < 100) {
        this.count += 20
        this.$refs.infiniteLoading.stateChanger.loaded()
      } else {
        this.$refs.infiniteLoading.stateChanger.complete()
      }
    }, 1000)
  }
}
```

今回は`No more data :)`という文字列を出すためにカウント値で条件を書いてますが、実際のリストとかなら`length`を使って合計値を取り、加算されたcount数とで比較するといいかなと思います。

```js
if (this.count < hogehoge.length) {
  this.count += 20
  this.$refs.infiniteLoading.stateChanger.loaded()
} else {
  this.$refs.infiniteLoading.stateChanger.complete()
}
```

デフォルトだと表示するデータが取得できなくなった場合`No more data :)`になっていますが、変更したい場合はtemplate側に`<span slot="no-more">hogehoge</span>`を書き込むと文言を変更することができます。

```js
<infinite-loading 
  ref="infiniteLoading" 
  spinner="spiral"
  @infinite="infiniteHandler">
  <span slot="no-more">もうないよ〜</span>
</infinite-loading>
```

# ローディングのカスタマイズ
このプラグインは便利なことにローディング時のspinerを変えることが可能です。
vue-infinite-loadingでは5つ用意されてます。
### default
![loading_default.gif](https://qiita-image-store.s3.amazonaws.com/0/271450/a511517d-6b41-08fb-44ff-bf37061a976e.gif)

### spiral
![loading_spiner.gif](https://qiita-image-store.s3.amazonaws.com/0/271450/fcb74c1b-a63d-952f-4f48-8a8b6b1f2ec1.gif)

### circle
![loading_circle.gif](https://qiita-image-store.s3.amazonaws.com/0/271450/883e2bbe-aee5-40a9-7347-45d6dc5b9e96.gif)

### bubbles
![loading_bubbles.gif](https://qiita-image-store.s3.amazonaws.com/0/271450/360c2b69-bb76-24b5-e97d-8c77113d8f3c.gif)

### waveDots
![loading_wavedots.gif](https://qiita-image-store.s3.amazonaws.com/0/271450/0988a9e7-c92d-6aa1-1df9-f21a9b8fa708.gif)

自分でカスタマイズしたローディングのspinerにするにはtemplate側に以下を追加するとできます。

```vue
<infinite-loading 
  ref="infiniteLoading" 
  @infinite="infiniteHandler">
  <div slot="spinner">
    <img src="hogehoge">
  </div>
</infinite-loading>
```
`<div slot="spinner"></div>`で囲み、その中に表示したい画像を入れると、その画像がspinerとして指定することが可能です。

# まとめ
今回初めて無限スクロールをvue-infinite-loadingを使って実装してみましたが、すごい使いやすいプラグインでした。
ドキュメントもかなり分かりやすくまとめてあったので導入自体もそこまで時間がかからずにできました。
もじ無限スクロールを実装することがあったらオススメのプラグインなので使ってみてください。

今回作ったDEMOのコードはgithubに掲載しているので、vue-infinite-loadingを使う機会があったらご参照ください。
https://github.com/ebarakazuhiro/blog/tree/master/infinite_loading