【ライブラリ無し】Laravel + vue で無限スクロール(infinite scroll)を1から実装 - inokawablog

    【ライブラリ無し】Laravel + vue で無限スクロール(infinite scroll)を1から実装

    pinterst,twitter,facebookなど、最近ではほぼ必ずと言っていいほど使われている無限スクロールをライブラリを使わずスクラッチでLravel と vue.js で実装する。

     

    Laravel Framework 5.8.35

    vue.js 2.5.17

    axios 0.19.0

     

    フロント

    <template>
      <div class="content">
        <div class="items">
          <div v-for="(item, itemIndex) in items">
            <p>{{item.name}}</p>
          </div>
        </div>
        <!-- ローディングアニメーション -->
        <div class="loading-animation" v-if="itemLoading">
          <img src="https://www.wp-master.club/wp-content/uploads/2018/10/loading.gif" alt="">
        </div>
      </div>
    </template>
    
    <script>
      export default {
        data: () => ({
          itemLoading: false,
          load: true,
          page: 1,
          items: [],
        }),
    
        mounted(){
          this.clearVar()
          window.onscroll = () => {
            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>

     

    mountedのタイミングで画面高さを取得して、bottomに言ったらgetItemsが発火します。getItemsはapiでcontrollerからデータを持ってきているだけです。

     

    難しいことはしてません。上からゆっくり読んでいけばわかります。

     

    バックエンド

    controller

    paginateで持ってくる

    public function getItems()
      {
        $items = Item::latest()->paginate(10);
        return ['items' => $items];
      }

     

     

    まとめ

    融通が効かない場合もあったりするので、なんでもライブラリを使わず、できるものはなるべく自作していきたい。