Vueで無限スクロールを実装する

imatomix
2017年12月3日 13:42

ゴール

  • ページの下までスクロールしたら、APIを叩いて次のコンテンツを受け取る

ざっくりの流れ

  • API側でページ単位のコンテンツ情報を投げてもらう
  • Vue側でスクロールで下まで来たら次のページのAPIを叩いてコンテンツ情報をもらう。
  • あんまりVue関係ない。

スクリプト

API

APIを叩くと、仮にこんな感じのjsonが返ってくる。
{ "page": 1, "pages": 4, "projects": [ { "author": { "name": "Keita Imatomi", "portrait": "user/0001/thumbnail.jpg", "username": "imatomix" }, "id": 2, "public": true, "thumbnail": "project/0022/thumbnail.jpg", "title": "zcvz" }, { "author": { "name": "Keita Imatomi", "portrait": "user/0001/thumbnail.jpg", "username": "imatomix" }, "id": 3, "public": true, "thumbnail": "project/0021/thumbnail.jpg", "title": "asd" }, ... ] }

Vue

<template> <article id="gallery"> <div class="grid"> <div class="col-xs-6 col-sm-4 col-md-3 col-lg-2 col-xl-2" v-for="project in projects" :key="project.id" v-if="project.public"> <Card :project="project"></Card> </div> </div> <div id="infscr-loading" v-if="isLoading"> <img src="/static/image/icon_loading.gif"> </div> </article> </template> <script> import axios from 'axios' import Card from '../ui/Card.vue' const URL = '/api/v1/projects/' export default{ components: { Card }, data: function(){ return { projects: [], page: 1, // 次に読み込むページ数 isLoading: false } }, // 最初に1ページ目を読み込む。スクロールイベントリスナーを登録する。 created: function(){ this.fetchProjects() window.addEventListener('scroll', this.scroll) }, destroyed: function(){ window.removeEventListener('scroll', this.scroll) }, methods:{ fetchProjects: function(){ if(this.isLoading == false){ this.isLoading = true axios.get(URL + this.page) .then((response) => { this.projects = this.projects.concat(response.data.projects) this.page++ // 次のページがページ総数を上回ったらisLoadingをundefineにして読み込み停止 this.isLoading = (this.page > response.data.pages)? undefined : false }) .catch((error) => { console.log(error) }) } }, scroll: function(e){ // #galleryの底辺が画面に入ったら次のページを読み込む if(gallery.getBoundingClientRect().bottom < window.innerHeight){ this.fetchProjects() } } } } </script>