ども、@kimihom です。
久々に無限スクロールを実装する機会が 詠みラボで発生しました。そこで、振り返りがてら、こんな感じで実装するのが個人的に一番シンプルだったコードをご紹介します。
サーバー側実装
俳句(Haiku) をそれぞれ20句ごとに毎回取得し、スクロール下部についたら新しく20件を取得します。HTMLの生成は Rails サーバー側で実施し、それをフロントエンド側では単に HTML を追加するだけの処理になっています。
# Gemfile gem "kaminari" # config/routes.rb resources :haiku # app/models/haiku.rb class Haiku < ApplicationRecord paginates_per 20 end # app/controllers/haiku_controller.rb class HaikuController < ApplicationController before_action :authenticate_user!, only: [:new, :create, :update] def index @haikus = Haiku .page(params[:page]) .order("created_at DESC") # 重要. スクロール時はlayoutを含めない return render layout: false if params[:no_layout] end end
<%# app/views/haiku/index.html.erb %> <div id="haikuCmp"> <% @haikus.each do |haiku| %> <div class="ku"> <%= haiku.kigo #etc %> </div> <% end %> </div>
// app/assets/javascripts/haiku.js $(function() { let isScrollLoading = false; let scrollPage = 1; $(window).scroll(function() { if (!isScrollLoading && $(window).scrollTop() + $(window).height() > $(document).height() - 100) { isScrollLoading = true; scrollPage += 1; $.ajax({url: "/haiku", data: { "page": scrollPage, "no_layout": "true" }}).done(function(data) { let appends = $(data).find(".haikusZone").html(); if (appends.trim().length == 0) return; $("#haikuCmp .haikusZone").append(appends); isScrollLoading = false; }).fail(function(e) { console.error("error", e); }) } }); });
ポイント
ほとんどが Rails での基本コードに近いです。唯一 "重要" と記した場所を詳しく解説します。
# 重要. スクロール時はlayoutを含めない return render layout: false if params[:no_layout]
まず、ここには if 文となっています。no_layout
のパラメータがない限りここを通らずに 通常の app/views/layouts/application.html.erb
が呼ばれ、基本のヘッダで CSS, JavaScript などの読み込みなどのコード全てが含まれるようになっています。
しかし、スクロールした後のHaiku一覧取得では、あくまでHaikuの追加したいリストだけを返すようにします。そのため、layout: false
を定義しています。これを定義せずに、スクロールして返すHTMLでも<html><head>...
が返ってくると、実装はより面倒になります。以下の3行でシンプルに収まるコードになりませんので、実際どうなるか、気になる方は調べてみてください。
let appends = $(data).find("#haikuCmp").html(); if (appends.trim().length == 0) return; $("#haikuCmp").append(appends);
個人的なお気に入りは $(data).find("#haikuCmp").html();
です。no_layout: true
でAjaxで送ったサーバーから 、レスポンスがきたHTMLを、一括で追加 append
するだけです。まさに意図した通りに動きます。
サーバーから#haikuCmp
の中身が空白以外の何もないデータが返れば、もうそれ以上データがないとしてスクロールを停止します。
終わりに
「いやいや、まだ jQuery かよ・・」そんな声が聞こえてきそうな記事です。
jQuery で慣れたら秒速でコードを組み立てることができるようになりました。この開発スピード感が楽しく、個人開発を進めるモチベーションに繋がっています。
引き続きこっそり改善を続けていきたいと思います。