無限スクロールとはスクロールすると次の記事やコンテンツが表示される機能です。
制作物にあるTypingGameのトップページが無限スクロールを実装しています。実際の挙動はそちらをご覧ください。
axiosで取ってくるのでapi.phpに以下のルーティングを設定します。
Route::get('/items', 'Api\ItemsController@getItems')->name('api.get');
次にコントローラーを設定します。
Itemモデルはあらかじめ作っておいてください。
use App\Models\Item;
public function getItems()
{
$items = Item::latest()->paginate(10); //1ページあたり10件表示を降順でとってくる指定
return ['items' => $items]; //returnする
}
以上で、Laravel側の設定は完了です。
次にVue側の設定を行います(あらかじめLaravelでVueが使えるように設定しておく)。
Vueのコンポーネントが使えるようにbladeを設定します。
app/Http/Controllers/Api/ItemsController.php
@extends('layouts.app')
@section('content')
<top-page></top-page>
@endsection
<template>
<div class="content">
<div class="items">
<div v-for="(item, itemIndex) in items" :key="itemIndex">
<p>{{item.name}}</p>
</div>
</div>
<!-- ローディング -->
<div class="loading-animation" v-if="itemLoading">
読み込み中です。
</div>
</div>
</template>
<script>
export default {
data: () => ({
itemLoading: false,
load: true,
page: 1,
items: [],
}),
mounted(){
this.clearVar()
window.addEventListener('scroll', () => {
let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight == document.documentElement.offsetHeight;
if (bottomOfWindow) this.getItems();
};
this.getItems()
},
methods: {
clearVar() {
this.itemLoading = false
this.load = true
this.page = 1
this.items = []
},
async getItems() {
if (this.load) { //全体の読み込み
if (!this.itemLoading) { //読み込み中は読み込めないようにする
this.itemLoading = true
try {
const response = await axios.get('/api/items?page=' + this.page)
if (response.data.items.last_page == this.page) this.load = false
if (response.data.items.data) {
await response.data.items.data.forEach((n,i) => {
this.items.push(n)
})
}
this.page += 1
} catch (e) {
console.log(e.response)
this.load = false
this.itemLoading = false
} finally {
this.itemLoading = false
}
}
}
},
}
}
</script>
ただし、このままだとscrollイベントがスクロールされる度に発火し、負担がかかるので
lodashを用いて制御します。
$ npm install --save lodash
window._ = require('lodash');
TopPage.vueのmounted()の部分を変更します。
mounted() {
this.clearVar();
window.addEventListener('scroll', _.throttle(() => {
let bottomOfWindow = document.documentElement.scrollTop + window.innerHeight == document.documentElement.offsetHeight;
if (bottomOfWindow) this.getItems();
}, 200, { trailing: true, leading: true }));
this.getItems();
},
lodashのthrottleのオプションについては以下が詳しいです。
https://www.webprofessional.jp/throttle-scroll-events/
https://liginc.co.jp/371432