瀑布流无限加载数据分页案例
效果
项目结构图
实体类
/*
新闻实体类
*/
public class News {
private Integer id; //主键id
private String title; //新闻标题
public News() {
}
public News(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
Mysql数据准备
-- 创建db11数据库
CREATE DATABASE db11;
-- 使用db11数据库
USE db11;
-- 创建数据表
CREATE TABLE news(
id INT PRIMARY KEY AUTO_INCREMENT, -- 主键id
title VARCHAR(999) -- 新闻标题
);
-- 插入数据
DELIMITER $$
CREATE PROCEDURE create_data()
BEGIN
DECLARE i INT;
SET i=1;
WHILE i<=100 DO
INSERT INTO news VALUES (NULL,CONCAT('奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实”',i));
SET i=i+1;
END WHILE;
END
$$
-- 调用存储过程
CALL create_data();
生成的表格
DAO层
public interface NewsMapper {
/*
查询全部
*/
@Select("SELECT * FROM news")
public abstract List<News> selectAll();
}
Service层
接口
public interface NewsService {
/*
分页查询
*/
public abstract Page pageQuery(Integer start, Integer pageSize);
}
实现类
public class NewsServiceImpl implements NewsService {
@Override
public Page pageQuery(Integer start, Integer pageSize) {
InputStream is = null;
SqlSession sqlSession = null;
Page page = null;
try{
//1.加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过SqlSession工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//4.获取NewsMapper接口的实现类对象
NewsMapper mapper = sqlSession.getMapper(NewsMapper.class);
//5.封装Page对象 start:当前页码 pageSize:每页显示的条数
page = PageHelper.startPage(start,pageSize);
//6.调用实现类对象的查询全部方法,此时底层执行的就是MySQL的limit分页查询语句
mapper.selectAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
//7.释放资源
if(sqlSession != null) {
sqlSession.close();
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//8.返回page对象
return page;
}
}
Servlet层
@WebServlet("/newsServlet")
public class NewsServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求和响应的编码
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset=UTF-8");
//1.获取请求参数
String start = req.getParameter("start");
String pageSize = req.getParameter("pageSize");
//2.根据当前页码和每页显示的条数来调用业务层的查询方法,得到分页Page对象
NewsService service = new NewsServiceImpl();
Page page = service.pageQuery(Integer.parseInt(start), Integer.parseInt(pageSize));
//3.将得到的数据转为JSON
String json = new ObjectMapper().writeValueAsString(page);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//4.将数据响应给客户端
resp.getWriter().write(json);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
}
html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>网站首页</title>
<link rel="stylesheet" href="css/tt.css">
</head>
<body>
<div class="top">
<span class="top-left">下载APP</span>
<span class="top-left"> 北京 晴天</span>
<span class="top-right">更多产品</span>
</div>
<div class="container">
<div class="left">
<a>
<img src="img/logo.png"><br/>
</a>
<ul>
<li>
<a class="channel-item active" href="#">
<span>
推荐
</span>
</a>
</li>
<li><a class="channel-item" href="#">
<span>
视频
</span>
</a></li>
<li><a class="channel-item" href="#">
<span>
热点
</span>
</a></li>
<li><a class="channel-item" href="#">
<span>
直播
</span>
</a></li>
<li><a class="channel-item" href="#">
<span>
图片
</span>
</a></li>
<li><a class="channel-item" href="#">
<span>
娱乐
</span>
</a></li>
<li><a class="channel-item" href="#">
<span>
游戏
</span>
</a></li>
<li><a class="channel-item" href="#">
<span>
体育
</span>
</a></li>
</ul>
</div>
<div class="center">
<ul class="news_list">
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实11”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实22”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实33”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实44”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实55”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实66”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实77”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实88”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实99”
<hr>
</a>
</div>
</li>
<li>
<div class="title-box">
<a href="#" class="link">
奥巴马罕见介入美国2020大选,警告民主党参选人须“基于现实1010”
<hr>
</a>
</div>
</li>
</ul>
<div class="loading" style="text-align: center; height: 80px">
<img src="img/loading2.gif" height="100%">
</div>
<div class="content">
<div class="pagination-holder clearfix">
<div id="light-pagination" class="pagination"></div>
</div>
</div>
<div id="no" style="text-align: center;color: red;font-size: 20px"></div>
</div>
</div>
</body>
<script src="js/jquery-3.3.1.min.js"></script>
<script>
//1.定义发送请求标记
let send = true;
//2.定义当前页码和每页显示的条数
var start = 1;
var pageSize = 10;
//3.定义滚动条距底部的距离
let bottom = 1; //数值越大刷新越快
//4.设置页面加载事件
$(function () {
//5.为当前窗口绑定滚动条滚动事件
$(window).scroll(function () {
//6.获取必要信息,用于计算当前展示数据是否浏览完毕
//当前窗口的高度
let windowHeight = $(window).height();
//当前滚动条从上往下滚动的距离
let scrollTop = $(window).scrollTop();
//当前文档的高度
let documentHeight = $(document).height();
//7.计算当前展示数据什么时候浏览完毕
//当 滚动条距底部的距离 + 当前滚动条滚动的距离 + 当前窗口的高度 >= 当前文档的高度
if ((bottom + windowHeight + scrollTop) >= documentHeight){
//8.判断请求标记是否为true
if (send == true){
// 如果当前页大于10,则将加载动图隐藏并结束方法
if (start == 10){
$(".loading").hide();
return;
}
//9.将请求标记置为false,当前异步操作完成前,不能重新发起请求
send = false;
//10.根据当前页和每页显示的条数来 请求查询分页数据
queryByPage(start,pageSize);
//11.当前页码+1
start ++;
}
}
});
});
//请求查询分页数据的函数
function queryByPage(start,pageSize) {
//将加载动图显示
$(".loading").show();
//发起AJAX异步请求
$.post({
url: "newsServlet",
data: {"start":start, "pageSize":pageSize},
success: function (data) {
if(data.length == 0) {
$(".loading").hide();
$("#no").html("我也是有底线的...");
return;
}
//加载动图隐藏
$(".loading").hide();
//将数据显示
let titles = ``;
for (let i = 0; i < data.length; i++){
titles += `
<li>
<div class="title-box">
<a href="#" class="link">
${data[i].title}
<hr>
</a>
</div>
</li>`;
}
//追加到页面
$(".news_list").append(titles);
//将请求标记置为true
send = true;
}
});
}
</script>
</html>
小结
-
如何确定当前显示的数据已经浏览完毕?
公式:(滚动条距底部的距离 + 滚动条上下滚动的距离 + 当前窗口的高度) >= 当前文档的高度
例如: 当前文档高度:存储10条数据,100px。
滚动条距底部的距离:1px。
当前窗口的高度:80px。
滚动条上下滚动的距离:>=19px。
-
知识点
方法 说明 $(function(){}) 页面加载事件 $(window) 获取当前窗口对象 scroll() 鼠标滚动事件 $(window).height() 当前窗口的高度 $(window).scrollTop() 滚动条上下滚动的距离 $(document).height() 当前文档的高度