RailsでInfiniteScrollしたので書きます。
現在ロードされているコンテンツを一番下まで見たら続きがロードされるあれです。
使ったもの
Rails 5.2
kaminari(https://github.com/kaminari/kaminari)
InfiniteScroll(https://github.com/metafizzy/infinite-scroll)
やったこと
- 適当なデータを250レコード登録
- 1ページあたり50件のページネーション実装
- InfiniteScrollする
できたもの
モデル
こちらよりモデルをお借りしました。
scaffoldでモデル作成
rails g scaffold Shop name zipcode address tel
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書く
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導入
gem 'kaminari'
bundle installしたらscaffoldで作ったshops_controllerとviewをいじります。
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
# 以下略
h1 Listing shops
#shops
= render partial: 'shop', collection: @shops
= paginate @shops
※ slimです。他のテンプレートエンジンならいい感じに読みかえてください。
デフォルトで書かれてるものは全部消してこれに置き換えれば大丈夫です。
= render partial: 'shop'
で呼んでるpartialはこちら
.shop
= "#{shop.name}: #{shop.zipcode}"
ここまでで、こんな感じのページネーションが完成するはずです。
そしたら次はInfinite Scrollです。
Infinite Scroll
InfiniteScroll(https://github.com/metafizzy/infinite-scroll)からinfinite-scroll.pkgd.min.js
をもらってきて、/app/assets/javascripts/
に置きます。(読めるとこならどこでもいいです)
したらapplication.jsにrequireを追加します。
//= require infinite-scroll.pkgd.min
これで準備完了です。あとはこいつの動作をさっきのviewに合わせて、scaffoldでできたshops.coffeeに書いていきましょう。
coffeeじゃなくて普通のjs書くならいい感じに(略)
$(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を変更しましょう。
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)からどうぞ。
以上
ハッピースクロールライフを。