瀑布流案例
封装jQuery瀑布流插件
//特点分析:
//1. 跟以前的瀑布流不一样的是,这次的瀑布流固定版心为1200px
//2. 瀑布流固定摆放5列,每一列的宽度固定为232px。
//思路分析:
//1. 计算每一列之间的缝隙
//2. 初始化一个数组,用户存储每一列的高度 [0,0,0,0,0]
//3. 查找数组的最小列,每次都把图片定位到最小列的位置
//4. 更新数组最小列的高度(加上定位过来的图片的高度)
代码参考:
jquery.waterfall.js
// 瀑布流具体实现
// 1. 获取父盒子和子盒子, 获取父盒子和子盒子的宽度
// 2. 计算间隙
// 3. 遍历子盒子, 进行设置位置 left, top
// (1) 第一行
// (2) 第一行以外的盒子
// jQuery 插件实现
// 给 jQuery 原型添加了一个方法
$.fn.waterFall = function() {
// this 就是一个 jQuery 对象
var $box = this; // 父盒子
var $items = $box.children(); // 所有子盒子
var boxWidth = $box.width(); // 父盒子的宽度
var itemWidth = $items.width(); // 获取子盒子的宽度, 返回第一个盒子的宽度
// 设定 5 列
var columns = 5;
// 计算间隙 = (父盒子的宽度 - 子盒子的宽度 * 列数) / (列数 - 1)
var space = (boxWidth - itemWidth * columns) / (columns - 1);
// 准备一个数组, 专门用于存放每一列的高度
var arr = [ 0, 0, 0, 0, 0 ];
// 遍历子盒子, 设置 left 和 top
$items.each(function( index, element ) {
// 遍历数组, 求最小列和最小列索引
var min = arr[0];
var minIndex = 0;
for ( var i = 0; i < arr.length; i++ ) {
if ( min > arr[i] ) {
min = arr[i]; // 更新最小列
minIndex = i; // 更新索引
}
}
// 设置盒子的位置, 设置 left 和 top
$(this).css({
left: minIndex * ( itemWidth + space ),
top: min + space
});
// 设置完盒子的位置后, 需要更新最小列
arr[ minIndex ] = min + space + $(this).height();
});
// 给父盒子设置高度, 求数组最大值
var maxHeight = Math.max.apply( null, arr );
$box.height( maxHeight );
}
瀑布流完整版
//需求分析:
//1. 页面刚开始,没有任何一张图片。因此需要从通过ajax获取图片
//2. 使用模版引擎将获取到的数据渲染到页面
//3. 因为图片路径是从服务端获取的,加载需要时间,需要等待图片加载完成后才能使用瀑布流进行布局。
//4. 给window注册scroll事件,当触底时,需要动态的加载图片。
//5. 加载时,显示加载中的提示信息,并且要求不能重复发送ajax请求
//6. 当服务端返回图片数量为0时,提示用户没有更多数据。
接口文档
//接口说明:瀑布流分页数据
//接口地址:data.php
//请求方式:get
//接口参数:page 当前是第几页 pageSize 当前页需要显示多少条
//返回类型 json
//返回数据:
{
page: 2,
items:[
{path: "./images/1.jpg",text:'这是描述信息'},
{path: "./images/2.jpg",text:'这是描述信息'}
{path: "./images/2.jpg",text:'这是描述信息'}
]
}
//page 下一页的页码
//items 返回当前页的数据
//path 图片地址
//text 文字
代码实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>封装jquery插件</title>
<style>
body {
margin: 0;
padding: 0;
font-family: "Microsoft Yahei";
}
.box {
position: relative;
width: 1200px;
margin: 0 auto;
}
.item {
width: 232px;
position: absolute;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
overflow:hidden;
}
.item > img {
width: 100%;
display: block;
}
.item > p {
margin: 0;
padding: 10px;
background: #eee;
}
.btn {
width: 280px;
height: 40px;
margin: 30px auto;
text-align: center;
line-height: 40px;
background-color: #CCC;
border-radius: 6px;
font-size: 24px;
cursor: pointer;
}
.loading {
/* transparent 透明色 */
background-color: transparent;
}
</style>
</head>
<body>
<div class="box">
<!-- <div class="item ">
<img src="./images/1.jpg" alt="">
<p>花非花,雾非雾,夜半来,天明去,来如春梦不多时,去似朝云无觅处。花非花,雾非雾,夜半来,天明去,来如春梦不多时,去似朝云无觅处。</p>
</div> -->
</div>
<div class="btn">加载更多</div>
</body>
<script src="js/jquery-1.12.4.js"></script>
<script src="js/jquery.waterfall.js"></script>
<!-- 1. 引包 -->
<script src="js/template-web.js"></script>
<!-- 2. 准备模板 -->
<script type="text/html" id="tpl">
{{ each items v i }}
<div class="item ">
<img src="{{ v.path }}" width="{{v.width}}" height="{{ v.height }}" alt="">
<p>{{ v.text }}</p>
</div>
{{ /each }}
</script>
<script>
// $('.box').waterFall(); 可以实现瀑布流布局
var currentPage = 1; // 表示当前页
var pageSize = 10; // 每页多少条
// 一进入页面, 需要 render() 一次
render();
function render() {
// 1. 一进入页面, 发送 ajax 请求, 获取第一页的数据(假设1页10条),
// 2. 得到数据通过模板引擎渲染
$.ajax({
type: "get",
url: "data.php",
data: {
page: currentPage,
pageSize: pageSize
},
dataType: "json",
beforeSend: function() {
// 每次请求前, 让按钮, 变成正在加载中..
$('.btn').html( "正在加载中..." ).addClass("loading");
},
success: function( info ) {
// 3. 准备数据 得到 info
// 4. 将数据和模板相结合 template( 模板id, 数据对象 );
// 在模板中可以使用 数据对象的属性
console.log( info );
var htmlStr = template( "tpl", info );
// 注意: 是 append 在原有的基础上进行追加
$('.box').append( htmlStr );
// 调用插件方法, 实现瀑布流布局
$('.box').waterFall();
// 布局完成, 需要恢复按钮成 加载更多
$('.btn').html("加载更多").removeClass("loading");
// 更新下一次渲染的页面
currentPage = info.page;
if ( info.items.length === 0 ) {
// 没有更多数据了, 添加 loading 是为了背景色, 且可以防止再次请求
$('.btn').html("没有更多数据了").addClass("loading");
}
}
})
}
// 需求1: 点击加载更多按钮, 应该重新发送ajax请求, 请求下页的数据, 进行页面渲染
$('.btn').click(function() {
// 需要判断, 阻止重复提交
if ( $('.btn').hasClass("loading") ) {
// 请求已经发送中
return;
}
// 调用 render 进行页面渲染
render();
});
// 需求2: 滚动到显示最后一个盒子的时候, 认为抵达了底部, 需要加载更多
$(window).scroll(function() {
console.log( 11111111 );
// if ( $('.btn').hasClass("loading") ) {
// // 请求已经发送中
// return;
// }
// 如果 最后一个盒子到页面顶部的距离 < 页面卷去的高度 + 可视区的高度, 认为进入屏幕了
// offset().top 可以获取当前盒子到页面顶部的位置
// offset() 返回一个对象
// top: 当前盒子到页面顶部的距离
// left: 当前盒子到页面最左边的距离
var lastTop = $('.box .item:last-child').offset().top;
var scrollTop = $(window).scrollTop(); // 页面卷去的高度
var height = $(window).height(); // 获取可视区域高度
if ( lastTop < scrollTop + height ) {
// 说明最后一个盒子进行可视区了
// 加载更多
render();
}
})
</script>
</html>
<?php
header('Content-Type:application/json; charset=utf-8');
/*获取数据 字符串*/
$data = file_get_contents('data.json');
/*转化php对象? 需要对其操作*/
$data = json_decode($data);
/*页码*/
$page = $_GET['page'];
/*条数*/
$pageSize = $_GET['pageSize'];
/*获取数据的起始索引*/
$offset = ($page - 1) * $pageSize;
/*slice 从什么位子开始切割 切割多少条*/
$result = array_slice($data, $offset, $pageSize);
/*下一页的页码*/
$page++;
/*转化json字符串 输出到前台*/
echo json_encode(array('page'=>$page, 'items'=>$result));/*{items:[]}*/
sleep(1);
?>