2017-12-3 22:26
vue

Vueで無限スクロール

ゴール

  • ページの下までスクロールしたら、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

projects.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>