随着现代浏览器性能的提升,前端工程师设计出的交互方式也多种多样。其中瀑布流方式滚动更新加载已经是一种常见的 Web 前端交互方式了。
然而在 Rails 中如何实现这样一种随着用户滚动页面就能自动追加内容到页面的方式呢?
有一些现成的 Gem 可以推荐,例如jquery-infinite-pages
和will_paginate_infinite
等。不过我觉得它们使用比较复杂,不如自己去实现一个。
本文既然提到最方便,自然是需要用一种最小化改动的方式来实现这样的功能。
具体如何实现,请往下看。
首先假设我们要实现瀑布流式动态更新的对象是 Post(或者是 Article、News 或者其他),第一步我们需要在Gemfile
中加入以下两个 Gem:
gem 'will_paginate'
gem 'bootstrap-will_paginate'
然后执行bundle
,接着去修改posts_controller.rb
,修改其中的index
方法:
def index
@posts = Post.all.paginate(:page => params[:page], :per_page => 10)
respond_to do |format|
format.html
format.js
end
end
这里由于我们增加了 js 的渲染格式,所以要去views/posts
中添加一个index.js.erb
模板文件,内容如下:
$('#posts_list').append('<%= j render @posts %>');
<% if @posts.next_page %>
$('.pagination').replaceWith('<%= j will_paginate @posts %>');
<% else %>
$(window).off('scroll');
$('.pagination').remove();
<% end %>
上面的代码通过 js 定位页面中的 posts_list 作为要追加元素的目标,所以我们稍微修改一下views/posts/index.html.erb
,在其中加入posts_list
元素:
<div id="posts_list">
<%= render @posts %>
</div>
<div id="infinite-scrolling">
<%= will_paginate %>
</div>
在这段代码中,我们将@posts集合交给其他模板去渲染了,而这里暂时还没有用来渲染@posts的模板,所以要在views/posts
中创建一个_post.html.erb
模板文件,内容如下:
<div>
<h3><%= post.title %></h3>
<p><%= post.content %></p>
<hr/>
</div>
就这么简单,用来输出标题和内容。
最后关键的一步,需要创建一个事件监听器来捕获页面的滚动变化,所以在assets/javascripts/posts.coffee
中,加入以下代码:
$(document).on "turbolinks:load", ->
$(window).on 'scroll', ->
more_posts_url = $('.pagination .next_page a').attr('href')
if more_posts_url && $(window).scrollTop() > $(document).height() - $(window).height() - 60
$('.pagination').html('<img src="/assets/ajax-loader.gif" alt="Loading..." title="Loading..." />')
$.getScript more_posts_url
return
return
如此一来,就实现了通过 ajax 方式请求原来需要在下一页展现内容,并把内容追加到 index.html 的文章列表中,也就实现了瀑布流加载了。
一切修改好以后,重启 Rails 服务,在页面滚动一下试试吧。
本方法参考自https://www.sitepoint.com/infinite-scrolling-rails-basics/
本文同步发表于我的博客