使用will_paginate实现下拉滚动异步加载效果
由交互变更聊起
我们网站的结果页面可能有上百条数据,原本采用的是传统的分页模式,即点击“上一页”或“下一页”按钮进行翻页操作。最近进行了一次交互改版,新版的交互变更为当鼠标滚轮滚动到页面底部时,页面上自动加载出下一页的内容。这篇博客要介绍的就是怎样实现这种交互效果。
实现思路概述
在传统的分页模式下,当我们点击“下一页”按钮时,实际上是向后端发送了一个AJAX请求,在这个请求的URL中附带了参数page的信息,后端接收到请求后,根据page参数利用will_paginate取出分页后的数据,最后更新前端页面。
在新版交互模式下,其实只需要在原有的分页功能基础上做一个小更改:当鼠标滚轮滚动到页面底部时,向后端发送一个AJAX请求,请求的URL即传统的“下一页”的链接URL,后端处理逻辑几乎不需要改变,最后只需要将分页后的数据添加到原来页面的尾部即可。
动手实现
首先,我们需要将页面结构重新组织一下,大致变为下面这个样子:
<table>
<!-- 将包含数据的内容页面移入partial中 -->
<tbody id="内容页面id">
<%= render partial: "partial页面" %>
</tbody>
</table>
<%= will_paginate @分页实例变量 %>
接下来按照思路实现一下鼠标滚轮滚动到页面底部的效果:
$(window).scroll(function(){
//检测鼠标滚轮是否已经滚动到页面底部
if($(window).scrollTop() > ($(document).height() - $(window).height() - 50)){
//AJAX请求will_paginate的下一页的href
$.getScript($('.pagination .next_page').attr('href'));
}
});
这样AJAX请求已经能够发送到后端了,剩下的工作是修改一下controller执行后对应的.js.erb中的代码:
# 注意这里是append方法
$('#内容页面id').append('<%= j render(partial页面)%>');
# 需要更新一下底部的will_paginate页面的翻页按钮
$('.pagination').html('<%= j will_paginate(@分页实例变量) %>');
现在测试一下,会发现当我们鼠标滚轮滑动到页面底部时,确实会向后台发送AJAX请求了,但是却会连续发送多次重复的请求。现在需要回头检查一下javascript代码:
当我们通过getScript发送请求时,仍旧在滚动滚轮,这样$(window).scroll函数依然会被触发,当新的一页数据没有被加载出来时,if判断语句始终为true,所以会导致发送多次AJAX请求。
我们需要修改一下刚才的javascript代码:
$(window).scroll(function(){
//先取出下一页的url
url = $('.pagination .next_page').attr('href');
//将url作为if的一个判断条件,保证当前页面滚动到底部时只会触发一次ajax请求
if(url && $(window).scrollTop() > ($(document).height() - $(window).height() - 50)){
//这里将pagination的url替换成文字
$('.pagination').text("加载中...");
$.getScript(url);
}
});
再测试一下,会发现已经能够正常滚动加载了,但是当我们滚动到最后一页时,会看到will_paginate的翻页组件露了出来,稍稍修改一下我们的.js.erb:
<% if @分页实例变量.next_page %>
$('.pagination').html('<%= j will_paginate(@分页实例变量) %>');
<% else %>
$('.pagination').hide();
<% end %>
看起来差不多了。但是我们还需要考虑一种极端情况,如果页面中每页展示的数据很少,比如是下图这个样子,连滚动条都没有:

这种情况下$(window).scroll函数永远也不会被触发,所以我们还需要在前端javascript代码中补充一句:
$(window).scroll();
这样,我们就实现了一个完整的下拉滚动异步加载效果。
