LaravelとVue(axios)でVue-infinite-loadingで無限ローディングを実装する

# ツイッターとか使ってるとタイムラインを無限に更新するアレを実装してみる。

## 環境

- Laravel 5.7
- Vue.js 2.5.17
- axios 0.19

##　事前準備

- 上記の環境構築済み

## `Vue-infinite-loading`をインストール

これだけでインストールできます

```terminal
npm install vue-infinite-loading
```

## Laravel側の設定

### Migration

`database/migrations/2019_07_15_123456_create_posts_table.php`

リレーションなしでシンプルな記事一覧用のテーブル

```php:2019_07_15_123456_create_posts_table.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title')->comment('記事タイトル');
            $table->string('text')->comment('記事本文');
            $table->timestamps();

            $table->index('id');
            $table->index('title');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
```

### Model

`app/Post.php`

```php:Post.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    //記事データの取得
    static function getPostPage()
    {
        //10件データを取得する
        $data = Post::paginate(10);

        return $data;
    }
    
}
```

### Controller

`app/Http/Controllers/PostsController.php`

メソッドを呼び出す

```php:PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

class PostsController extends Controller
{
    public function blog()
    {
        $blogs = Post::getPostPage();

        return $blogs;
    }
}
```

### Routing

`routes/web.php`

URLで`/api/post`を叩くとデータを取得できる

```php:web.php
// Post
Route::get('api/post', 'PostsController@blog');
```

## Vue側の設定

### Vue-infinite-loadingを使用する

`resources/js/app.js`

```javascript:app.js
import './bootstrap';
import Vue from 'vue';
import Routes from './routes.js';
import InfiniteLoading from 'vue-infinite-loading';

//Vue-infinite-loadingを使用する
Vue.use(InfiniteLoading);

const app = new Vue({
    el: '#app',
    router: Routes,
    render: h => h(App)
});

export default app;
```

### コンポーネントを設定する

`resources/js/components/Blog.vue`

```js:routes.js
import Vue from 'vue';
import VueRouter from 'vue-router';

//ページコンポーネントをインポートする
import Blog from './components/Blog';

//VueRouterプラグインを使用する
Vue.use(VueRouter);

//パスとコンポーネントのマッピングを行う
const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/blog',
            name: 'Blog',
            component: Blog
        }
    ]
});

//app.jsでインポートするためにVueRouterインスタンスをエクスポートする
export default router;
```

### View

`resource/js/conponents/Blog.vue`

```vue:Blog.vue
<template>
    <div class="col-md-12">
        <div v-for="post in posts" :key="post.index">                                               
            <h1>{{ post.title }}</h1>
            <p :key="post.index">{{ post.text }}</p>
        </div>
        <infinite-loading @infinite="infiniteHandler"></infinite-loading>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                page: 1,
                posts: []
            };
        },
        methods: {
            infiniteHandler($state) {
                //web.phpで設定したルーティング
                axios.get('/api/post', {
                    params: {
                        page: this.page,
                        per_page: 1
                    },
                }).then(({ data }) => {
                    //そのままだと読み込み時にカクつくので1500毎に読み込む
                    setTimeout(() => {
                        if (this.page < data.data.length) {
                            this.page += 1
                            this.posts.push(...data.data)
                            $state.loaded()
                        } else {
                            $state.complete()
                        }
                    }, 1500)
                }).catch((err) => {
                    $state.complete()
                })
            }
        }
    };
</script>
```

これで動くはず。。( ◠‿◠ )

## 参考

[Vue-infinite-loading公式](https://peachscript.github.io/vue-infinite-loading/)
[Laravel Vue JS Infinite Scroll Example with Demo](https://itsolutionstuff.com/post/laravel-vue-js-infinite-scroll-example-with-demoexample.html)