はじめに
Railsで無限スクロールを実装してみたので、その備忘録的に投稿しようと思います。
kaminariというページネーションを簡単に実装できるgemを使い、無限スクロールを実装してみたいと思います。
無限スクロールにはjscrollというjQueryのライブラリを使います。
無限スクロールとは
無限スクロールはメルカリの商品一覧でも見る、下までスクロールすると新しい商品が自動的に読み込まれるあれです。
無限スクロールにはページネーションを先に実装する必要があります。
ページネーションにはkaminariというgemを使います。
Railsのバージョンは5です。
kaminariのインストール
gem 'kaminari'
を記載して、
bundle install
を実行するだけです。
jscrollのインストール
jscrollには現時点では(2019年2月)gemが存在しないと思われますので、公式のページからダウンロードしてきます。
なお、jscrollを使うにはjQueryが必要です。
railsでjQueryを使えるようにするにはこちら
- CDNで使えるようにする
手軽に試してみたい人はこちら。
<script src="https://cdnjs.cloudflare.com/ajax/libs/jscroll/2.4.1/jquery.jscroll.min.js"></script>
- ローカルに落とす
こちらのdistからjquery.jscroll.min.jsをダウンロードしてきます。
jscrollのGithub
そして、asset/javascripts配下にダウンロードしたjquery.jscroll.min.jsを置いて、(読み込めれば場所はどこでも)
//= require jquery.jscroll.min.js
を記載。
ページネーションを実装
今回はDBに登録してあったプログラミング言語を一覧で表示するだけの画面を作っていきたいと思います。
skillsというcontrollerを作成し、以下を記載。
class SkillsController < ApplicationController
def index
@skills = Skill.page(params[:page]).per(10)
end
end
.page(params[:page]).per(10)の部分が一画面に10個の要素を表示するということになります。
そして、index.html.erbに
<ul class="skill-list jscroll">
<% @skills.each do |skill| %>
<li><%= skill.skill_name %></li>
<% end %>
<%= paginate @skills %>
</ul>
<%= paginate @skills %>の部分がページの部分。
以上を記載すると、ページネーションが実装できます。とても簡単ですね。
以下のような画面になりました。
無限スクロールを実装
無限スクロールは以下のようにして実装できます。
以下のソースは画面を開いた段階で、次の要素が読み込まれる実装になります。
coffeescript
$ ->
$('.jscroll').jscroll
return
jQuery
$(function() {
$('.jscroll').jscroll;
});
ただ、これだけだと動きません・・・。次のページへのリンクを指定する必要があるためです。
このようにすると、画面を読み込むと自動的に次のページが読み込まれます。
coffeescript
$ ->
$('.jscroll').jscroll
nextSelector: 'span.next a'
return
jQuery
$(function() {
$('.jscroll').jscroll({
nextSelector: 'span.next a'
});
});
次のリンクを指定するにはnextSelectorを指定してやります。
ただ、ここれだけでは変な感じで読みこまれると思います。
読み込まれている場所はずれているし、jsのconsoleを見ると、rails-ujsが既に読み込まれていますよ、みたいなエラーが出ていると思います。
これは、次のページのhtmlを全て読み込んでしまっていて、javascriptなども重複して読み込んでしまっているのでエラーが出ています。
なので、次のページの読み込む要素を指定してやって、その要素だけ読み込ませるようにします。
coffeescript
$ ->
$('.jscroll').jscroll
contentSelector: '.skill-list'
nextSelector: 'span.next:last a'
return
jQuery
$(function() {
$('.jscroll').jscroll({
contentSelector: '.skill-list',
nextSelector: 'span.next:last a'
});
});
次にロードする要素として、ulの.skill-listを指定しています。
nextSelectorでspan.next:last aで:lastを指定しているのは、
読み込むリンクはhtmlを読み込んでいくとどんどん増えていきます。
なので、読み込まれた最後のリンクを指定してやることで、どんどん次のページを読み込むようにしています。
ulはpaddingが入ることを忘れていたので、
ul.skill-list {
padding: 0;
}
あとはページの部分が邪魔なので、
nav.pagination {
display: none;
}
でページ部分を表示させないようにする。
最終的な画面
後は、画面下までスクロールしたことをjavascriptで検知させて、$('.jscroll').jscrollを呼び出してやれば次の要素を読み込めます。
画面下までスクロールしたことを判定
こちらの記事を参考にさせて頂きました。
coffeescript
$(window).on 'scroll', ->
scrollHeight = $(document).height()
scrollPosition = $(window).height() + $(window).scrollTop()
if (scrollHeight - scrollPosition) / scrollHeight <= 0.05
# スクロールの位置が下部5%の範囲に来た場合
$('.jscroll').jscroll
contentSelector: '.skill-list'
nextSelector: 'span.next:last a'
return
return
jQuery
$(window).on('scroll', function() {
scrollHeight = $(document).height();
scrollPosition = $(window).height() + $(window).scrollTop();
if ( (scrollHeight - scrollPosition) / scrollHeight <= 0.05) {
$('.jscroll').jscroll({
contentSelector: '.skill-list',
nextSelector: 'span.next:last a'
});
}
});
これで、画面下までスクロールしたら自動的に、次の要素が読み込まれるようになります。
おわりに
ライブラリなどを使うと非常に簡単に無限スクロールが実装できます。
結構モダンなページがお手軽にできると思いますので、是非お試しあれ。