LoginSignup
35
35

More than 5 years have passed since last update.

Rails & kaminariで無限スクロール(Infinite Scroll)する

Last updated at Posted at 2018-10-14

RailsでInfiniteScrollしたので書きます。
現在ロードされているコンテンツを一番下まで見たら続きがロードされるあれです。

使ったもの

Rails 5.2
kaminari(https://github.com/kaminari/kaminari)
InfiniteScroll(https://github.com/metafizzy/infinite-scroll)

やったこと

  1. 適当なデータを250レコード登録
  2. 1ページあたり50件のページネーション実装
  3. InfiniteScrollする

できたもの

infinite.mov.gif

モデル

こちらよりモデルをお借りしました。

scaffoldでモデル作成

rails g scaffold Shop name zipcode address tel 
create_shops.rb
class CreateShops < ActiveRecord::Migration[5.2]
  def change
    create_table :shops do |t|
      t.string :name
      t.string :zipcode
      t.string :address
      t.string :tel

      t.timestamps
    end
  end
end

seeds.rb書く

seeds.rb
250.times do |i|
  Shop.create!(
    name:    "店名#{i}",
    zipcode: "111-#{sprintf("%04d", i)}",
    address: "住所#{i}",
    tel:     "00-1234-#{sprintf("%04d", i)}"
  )
end

データ作成

rails db:migrate
rails db:seed

で250件のshopレコードができました。

kaminari導入

Gemfile
gem 'kaminari'

bundle installしたらscaffoldで作ったshops_controllerとviewをいじります。

shops_controller.rb
class ShopsController < ApplicationController
  before_action :set_shop, only: [:show, :edit, :update, :destroy]

  # GET /shops
  # GET /shops.json
  def index
    @shops = Shop.page(params[:page]).per(50) #1ページあたり50件表示
  end

  # 以下略

index.html.slim
h1 Listing shops

#shops
  = render partial: 'shop', collection: @shops
= paginate @shops

※ slimです。他のテンプレートエンジンならいい感じに読みかえてください。
デフォルトで書かれてるものは全部消してこれに置き換えれば大丈夫です。

= render partial: 'shop' で呼んでるpartialはこちら

_shop.html.slim
.shop
  = "#{shop.name}: #{shop.zipcode}"

ここまでで、こんな感じのページネーションが完成するはずです。
スクリーンショット 2018-10-14 15.17.55.png

そしたら次はInfinite Scrollです。

Infinite Scroll

InfiniteScroll(https://github.com/metafizzy/infinite-scroll)からinfinite-scroll.pkgd.min.jsをもらってきて、/app/assets/javascripts/ に置きます。(読めるとこならどこでもいいです)

したらapplication.jsにrequireを追加します。

application.js
//= require infinite-scroll.pkgd.min

これで準備完了です。あとはこいつの動作をさっきのviewに合わせて、scaffoldでできたshops.coffeeに書いていきましょう。
coffeeじゃなくて普通のjs書くならいい感じに(略)

shops.coffee
$(document).on 'turbolinks:load', ->
  $('#shops').infiniteScroll
    path: "nav.pagination a[rel=next]"
    append: ".shop"
    history: false
    prefill: true
    status: '.page-load-status'

ここまで書けばInfiniteScrollは動作するはずです。冒頭に貼ったgifとほぼ同じようになっていることと思います。

以下解説です。

  • infiniteScrollのセレクタには監視する対象を指定します。
  • pathには次のページへのリンクを指定します。今回はkaminariのnext >のセレクタを指定しています。
  • appendには、読み込んだ次ページの内容のうち、「この要素を対象としてappendする」ってのを指定します。// append .post elements from next page to container (原文)
    • 今回は.shopとしているので、読み込まれたpartialのうち .shop以下のみがappendされます。他に余計なものがあったとしてもそれをappendしないようにできるんですね。
  • historyは、読み込むたびにURLを書きかえるか指定します。history: 'push'にすると、読み込みのたびに?page=の値が変化していきます。
  • prefillはスクロールしきらないうちから読み込んじゃうかってやつです。これfalseにすると、一番下までスクロールしてからロードが始まるようになります。
  • statusは読み込み中や全部読み込んだ後に表示するものの設定です。

statusについて

InfiniteScrollのオプションで設定した status: '.page-load-status'について。

の前に、viewを変更しましょう。

index.html.slim
h1 Listing shops

#shops
  = render partial: 'shop', collection: @shops
.page-load-status
  .infinite-scroll-request
    | loading!!
    br
    = paginate @shops
  p.infinite-scroll-last
    | end of contents!!!
  p.infinite-scroll-error
    | this is error message

公式のドキュメントにはこう記載があります。

Displays status elements indicating state of page loading. Within the selected element:

.infinite-scroll-request element will be displayed on request
.infinite-scroll-last element will be displayed on last
.infinite-scroll-error element will be displayed on error

つまりそういうことです。
現在のロード状況に応じて、.page-load-status内の.infinite-scroll-requestやら.infinite-scroll-lastやらを出し分けてくれるんですね。素敵。

オプションはまだまだあるので、気になったらこちら(https://infinite-scroll.com/options.html)からどうぞ。

以上

ハッピースクロールライフを。

35
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
35