jq实现瀑布流布局
效果图预览
实现思路:根据网页宽度计算好一排有多少列图片,设置一个空数组记录每一列的高度变化,根据比较每一列的高度大小依次给最短的那一列插入图片
html代码:
<body>
<div class="waterfall-box"></div>
</body>
css代码:
*{
padding: 0;
margin: 0;
}
body,.waterfall-box{
width: 100%;
height: 100%;
}
.img-item{
display: flex;
flex-direction: column;
border-radius: 8px;
overflow: hidden;
position: absolute;
background: #ffffff;
box-shadow: 0 0 8px #ccc;
}
.img-item,.img-item img{
width: 290px;
height: auto;
display: block;
}
.content{
margin: 0 20px;
padding: 15px 0;
border-bottom: 1px solid #eee;
}
.user-info{
padding: 15px 20px;
display: flex;
flex-direction: row;
align-items: center;
}
.user-info .userimg img{
width: 40px;
height: 40px;
display: block;
border-radius: 50%;
}
.info{
margin: 0 0 0 10px;
display: flex;
flex-direction: column;
justify-content: center;
font-size: 14px;
}
.info span:nth-of-type(1){
color: rgb(197, 120, 20);
}
.info span:nth-of-type(2){
padding: 2px 6px;
margin: 5px 0 0 0;
color: rgb(255, 255, 255);
background: rgb(236, 164, 70);
border-radius: 20px;
font-size: 12px;
}
js代码:
// 瀑布流图片数组
let img_arr = [
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2258625464,2556143219&fm=26&gp=0.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-PKNWsLBzoa.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-JjxDKCWseA.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-oFRMxQtfkd.jpeg',
'http://image.biaobaiju.com/uploads/20180801/23/1533136201-VtUkzgfLxA.jpg',
'http://image.biaobaiju.com/uploads/20180801/23/1533136201-wUTXZRcgCp.jpg',
'http://image.biaobaiju.com/uploads/20181007/15/1538896968-DCWLNoEUJQ.jpg',
'http://image.biaobaiju.com/uploads/20181007/15/1538896972-fealVIJZhS.jpg',
'http://image.biaobaiju.com/uploads/20181007/15/1538896972-izKDXVkJOq.jpg',
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2258625464,2556143219&fm=26&gp=0.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-PKNWsLBzoa.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-JjxDKCWseA.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-oFRMxQtfkd.jpeg',
'http://image.biaobaiju.com/uploads/20180801/23/1533136201-VtUkzgfLxA.jpg',
'http://image.biaobaiju.com/uploads/20180801/23/1533136201-wUTXZRcgCp.jpg',
'http://image.biaobaiju.com/uploads/20181007/15/1538896968-DCWLNoEUJQ.jpg',
'http://image.biaobaiju.com/uploads/20181007/15/1538896972-fealVIJZhS.jpg',
'http://image.biaobaiju.com/uploads/20181007/15/1538896972-izKDXVkJOq.jpg',
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2258625464,2556143219&fm=26&gp=0.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-PKNWsLBzoa.jpg'
]
// 上拉加载图片虚拟数据
let data = [
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2258625464,2556143219&fm=26&gp=0.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-PKNWsLBzoa.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-JjxDKCWseA.jpg',
'http://image.biaobaiju.com/uploads/20180802/00/1533140278-oFRMxQtfkd.jpeg',
'http://image.biaobaiju.com/uploads/20180801/23/1533136201-VtUkzgfLxA.jpg',
'http://image.biaobaiju.com/uploads/20180801/23/1533136201-wUTXZRcgCp.jpg',
]
let win_width = $(window).width(); //获取网页宽度
let col_num = Math.floor(win_width / 310) //根据网页宽度计算多少列图片
let old_col_num = Math.floor(win_width / 310) //记录列数改变前上一次是多少列图片(此变量用于窗口宽度大小发生改变时)
let hei_arr = [] //记录每一列图片的总高度
let resort = true //网页窗口宽度改变后图片是否在重新排序的状态值
let loading = true //上拉加载的状态值
// 重新计算图片列数
resize();
$(window).scroll(function(){
let scroH = $(document).scrollTop(); //滚动条高度
let viewH = $(window).height(); //可见高度
let contentH = $(document).height(); //内容高度
// 当滚动条距离页面还有150px的时候加载图片
if(scroH + viewH + 150 >= contentH && loading){
// 修改加载状态
loading = false
// 在这里写ajax数据请求
// 将获取到的谁数据插入原有的数组
for(let i = 0;i < data.length; i++){
img_arr.push(data[i])
}
// 将新请求得到的数据排列
for(let i = 0;i < data.length; i++){
insertImg((img_arr.length - data.length) + i)
}
}
})
// 重新计算图片列数
function resize(){
$(window).resize(function(){
win_width = $(window).width();
old_col_num = Math.floor(win_width / 310) == 0 ? 1 : Math.floor(win_width / 310)
if(col_num !== old_col_num && resort == true){
col_num = old_col_num
resort = false
// 重新给图片排序
reSort()
}
})
}
// 首次加载页面
for(let i = 0 ; i < img_arr.length; i++ ){
if(i < col_num){
let top = 18 //设置图片模板的向上偏移值为18
let left = i == 0 ? 18 : 290 * i + 18 * (i + 1) //以18为基础值设置每个图片容器的向左偏移值
// 制作图片模板
module(img_arr[i],top,left,function(html){
// 返回的模板追加到页面
$('.waterfall-box').append(html)
if(i == col_num - 1){
// 当第一排图片全部插入完毕后开始计算每一列的高度
caluation(col_num)
}
})
}else{
// 从第二排开始插入图片
// 设置100毫秒的回调函数,预防图片过大加载过慢而都导致的无法获取图片宽高的问题
setTimeout(function(){
// 每次插入图片后给一个30毫秒的延迟
setTimeout(function(){
insertImg(i)
},30*i)
},100)
}
}
// 第一行图片排列完成后计算每一列的高度
function caluation(num){
let arr = []
for(let i = 0 ;i < num; i++){
// 获取到每一个图片模板的高度,给山下两图片模板增加18px的间距
let div_height = $('.img-item').eq(i).height() + 18
arr.push(div_height)
// 把第一排每一列的高度写进事先设置好的空数组
hei_arr = arr
}
}
// 插入图片
function insertImg(idx){
// 获取最小的高度值
let min_height = Math.min.apply(null, hei_arr)
// 获取最大的高度值
let max_height = Math.max.apply(null, hei_arr)
// 获取最小高度在数组里的下标
let min_index = hei_arr.indexOf(min_height)
let top = min_height + 18
let left = min_index == 0 ? 18 : 290 * min_index + 18 * (min_index + 1)
module(img_arr[idx],top,left,function(html){
$('.waterfall-box').append(html)
let div_height = $('.img-item').eq(idx).height() + 18
hei_arr[min_index] = hei_arr[min_index] + div_height
if(idx == img_arr.length - 1){
// 遍历到最后一张图片的时候
// 图片可进行重新排列
resort = true
// 修改状态可在此加载数据
loading = true
}
})
}
// 图片重新排序
function reSort(){
for(let i = 0; i < img_arr.length; i++){
if(i < col_num){
let top = 18
let left = i == 0 ? 18 : 290 * i + 18 * (i + 1)
$('.img-item').eq(i).animate({"top": top + 'px',"left": left + 'px'},200,function(){})
if(i == col_num - 1){
caluation(col_num)
}
}else{
setTimeout(function(){
let min_height = Math.min.apply(null, hei_arr)
let max_height = Math.max.apply(null, hei_arr)
let min_index = hei_arr.indexOf(min_height)
let top = min_height + 18
let left = min_index == 0 ? 18 : 290 * min_index + 18 * (min_index + 1)
let div_height = $('.img-item').eq(i).height() + 18
hei_arr[min_index] = hei_arr[min_index] + div_height
$('.img-item').eq(i).animate({"top": top + 'px',"left": left + 'px'},200,function(){
if(i == img_arr.length - 1){
resort = true
}
})
},80)
}
}
}
// 图片模板
function module(img,top,left,fun){
// img:图片链接
// top:模板到页面顶端的偏移值
// left:模板到页面顶端的偏移值
// fun:回调函数
let html = `
<div class="img-item" style="top:` + top + `px;left:` + left + `px">
<img src="`+ img +`">
<div class="content">
这是一个瀑布流的例子
这是一个瀑布流的例子
这是一个瀑布流的例子
</div>
<div class="user-info">
<div class="userimg">
<img src="http://pic.qqtn.com/up/2017-11/2017112717262155194.png">
</div>
<div class="info">
<span>白纸一张</span>
<span>白纸一张的博客</span>
</div>
</div>
</div>
`
fun(html)
}