jquery实现简单瀑布流布局

是开头都会说的原理

瀑布流布局有两种,一种是固定列,一种是非固定列。在此主要记述第一种的实现。

固定列的特征是:无论页面如何缩放,每行的总列数都一致。

一行4列的瀑布流从布局的角度来说,就是4个li标签。通过一定的事件(比如滚动条滚动多少px),然后读取之,再把数据动态地添加到页面中。

添加数据原则,不是根据li索引值来加,而是根据各列中高度最短的的那列动态添加。否则可能导致页面很难看(左右高度不统一)。

实例涉及ajax方法。可在服务器环境下运行。

废话不多说了。直接上样式。

    <ul id="ul1">
<li>
<div>
<img src="images/1.jpg">
<p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p>
</div>
</li>
<li>
<div>
<img src="images/2.jpg">
<p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p>
</div>
</li>
<li>
<div>
<img src="images/3.jpg">
<p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p>
</div>
</li>
<li>
<div>
<img src="images/4.jpg">
<p>我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述我是文字描述</p>
</div>
</li>
</ul>

css

*{
margin:0;
padding: 0;
} ul li{
list-style: none;
} #ul1{
width: 1080px;
margin: 100px auto 0;
} li{
width: 247px;
float: left;
margin-right: 10px;
}
li div{
border:1px solid #000;padding:10px;
margin-bottom:10px;
}
li div img{
width: 225px;display: block;
}

基本效果如图:



样式显示没问题之后,就把li里面的代码删掉。

接下来通过ajax来动态添加。

数据哪里来?

这里用的是wookmark的数据接口。

http://www.wookmark.com/api/json/popular?page=1

点开url得到是一个json。

信息量很大。怎么分析?

一般可以看文档。但是手头没有文档的情况下,可以看看链接。返回是什么鬼。

function createUrl(num){
return 'http://www.wookmark.com/api/json/popular?page='+num+'&callback=?';
} $(function(){
$.getJSON(createUrl(1),function(data){
console.log(data);
})
})

控制台打印结果为:



原来是一个50个图片信息组成的数组。每个数组元素都是一个json。在这个简单的demo里面,暂时只需要取preview属性和title属性就好了。

布局实现

关键之一在于,判断最短的li,事实上我们需要最短高度li的索引值。

//找出高度最小li的索引值
function getShortestLi(){
var shortest=0;
for(var i=1;i<4;i++){
if($('li').eq(i).height()<$('li').eq(shortest).height()){
shortest=i;
}
}
return shortest;
}

然后就是getJSON方法

$(function(){
$.getJSON(createUrl(1),function(data){
//console.log(data); for(var i=0;i<dataArr.length;i++){
var $html=$('<div><img src="'+data[i].preview+'"><p>'+data[i].title+'</p></div>');
//console.log($('li').eq(getShortestLi()).height())
$('li').eq(getShortestLi()).append($html);
};
console.log([$('li').eq(0).height(),$('li').eq(1).height(),$('li').eq(2).height(),$('li').eq(3).height()])
})
})

再加载看看,布局就出来了。简单又漂亮。

做到这里,看起来一切都挺好。然而潜伏着一个致命的问题。

for循环惹的祸?

看看console.log的信息。为了分析,我把4个li的高度放进了一个数组:



50张图片分4列,少说平均高度也得有三四千像素。

而到循环结束,程序判断的终点竟然只有令人发指的1000多个px,因为图片加载过程慢于for循环执行速度。虽然demo里的显示还算正常,但这种代码在网速不好时,会造成工作事故。

思路一:可以判断图片是否加载完成。

可以用个定时器监听下,然后用递归实现,我的方案是这样

                    var index=0;
function LoadPic(index){
var $html=$('<div><img src="'+data[index].preview+'"><p>'+data[index].title+'</p></div>')
$('li').eq(getShortestLi()).append($html); var oImg=$html.find('img');
var t=setInterval(function(){ if(oImg.height()!=0){//如果加载完了。
clearInterval(t);
//console.log([$('li').eq(0).height(),$('li').eq(1).height(),$('li').eq(2).height(),$('li').eq(3).height()])
if(index<50){
return LoadPic(index+1);
}else{
return false;
}
}else{
console.log('wait')
} },50)//每隔50ms监听一次 } LoadPic(0);

但是,从用户体验的角度来说,等一张图加载完成再进行下一张加载是不友好的。数据提供方都应该直接把图片的高度在服务器处理好,json数据里面返回过来。网速很慢的时候,要等好久,然后一下子图片都出来了,不觉得很诡异吗?尤其是第三方接口。一加载不出来就出大问题了。

所幸的是,第三方提供了图片的宽高信息。

因此for循环还是可以有的,在返回的数据里面,有宽度和高度值。利用它们就可以实现定宽(255px)和定高(原始高度乘上一个比例)。

$(function(){
$.getJSON(createUrl(1),function(data){ console.log(data); for(var i=0;i<data.length;i++){ //console.log(data[i].preview);
var $html=$('<div><img src="'+data[i].preview+'"><p>'+data[i].title+'</p></div>')
$('li').eq(getShortestLi()).append($html); $html.find('img').css('height',(data[i].height*225/data[i].width)+'px');
$html.find('img').css('width','225px');
}; //console.log([$('li').eq(0).height(),$('li').eq(1).height(),$('li').eq(2).height(),$('li').eq(3).height()])
})
})

事实上个人认为这是最简单且用户体验最好的方案。

有了瀑布,还需要流

流的逻辑

往下拉(滚动),第一个底部进入可视区的li,优先加载。



换句话说,最短li的高度与该li到页面顶部之和小于滚动条高度和可视区高度之和时,触发li加载。

li的高度好求。但是最短li到页面顶部距离怎么求?

原生的方法可以这样实现:

function getTop(obj){
var iTop=0;
while(obj){
iTop+=obj.offsetTop;
obj=obj.offsetParent;
}//累加元素本身和自身所有父级高度偏移值
return iTop;
}

但是本案例既然是用jquery,自然有它的方法。

obj.offset().top

滚动事件

原生的实现方法是:window.onscroll=function(){...}

jquery的实现方法是:$(window).scroll(function(){...})

现在验证一下写出的代码代码有没问题

    (window).scroll(function(){

        var $li=$('li').eq(getShortestLi());
var scrollTop=document.documentElement.scrollTop||document.body.scrollTop;
//console.log([$li.offset().top+$li.height(),document.documentElement.clientHeight+scrollTop])
//如果li高度与li到页面顶部的高度之和<可视区高度+滚动距离
if($li.offset().top+$li.height()<document.documentElement.clientHeight+scrollTop){
alert(1);
}
})

运行代码,发现第一个到底的li出现是可视区时,弹出1.证明可用。

因为涉及到滚动事件,所以getJSON相关函数应该封装为getList()方便调用。所以需要重新调整一下。

此时的代码是这样的:

//找出高度最小li的索引值
function getShortestLi(){
var shortest=0;
for(var i=1;i<4;i++){
if($('li').eq(i).height()<$('li').eq(shortest).height()){
shortest=i;
}
}
return shortest;
} function createUrl(num){
return 'http://www.wookmark.com/api/json/popular?page='+num+'&callback=?';
} function getList(n){
$.getJSON(createUrl(n),function(data){
//console.log(data); for(var i=0;i<data.length;i++){
var $html=var $html=$('<div><img src="'+data[i].preview+'"><p>'+data[i].title+'</p></div>');
//console.log(data[i].height);
$('li').eq(getShortestLi()).append($html);
dataArr[i].height*=225/dataArr[i].width;
$html.find('img').css('height',dataArr[i].height+'px');
$html.find('img').css('width','225px');
};
} $(function(){
var pageNum=1;
getList(pageNum);
$(window).scroll(function(){
var $li=$('li').eq(getShortestLi();
var scrollTop=document.documentElement.scrollTop||document.body.scrollTop; if($li.offset().top+$li.height()<document.documentElement.clientHeight+scrollTop){
pageNum++;
console.log(pageNum);
getList(pageNum);
}
})
})

这样一来,好像可以实现了。但是一看控制台的console.log,又发现问题。

如厕的逻辑

在触发加载前提时,图片正在加载,期间动了滚动条,就又触发第二次加载,再动一下,就触发第三次,于是短短一瞬间,触发了n次加载。

那就做一个开关吧。

就跟公厕逻辑一样。n个人排队进一个坑位。外面的人想要进去首先得判断门是否锁上了。没锁才能进。进去之后第一件事把门锁上。等如厕完毕,门就打开。后面的人才能进

新设置一个开关bCheck,默认为true。

到触发加载条件时,还要判断bCheck是否为真(门开),为真时才能触发getList()(如厕)。否则return false(只能等)。

getList一开始就把bCheck设为false(如厕前先锁门)。等到getList回调函数执行到尾声。再把bCheck设为true(开门)。

这一段不贴代码了。

总有流完的一天。

当数据结束时(所有人上完厕所),就没有必要再进行加载了(自动把门锁上)。

所以在getJSON回调函数内锁门之后发现进来的是个空数组,那就进行判断,当获取到data的length为空时,直接returnfalse。那么bCheck就永远关上了。

全部代码如下:

//找出高度最小li的索引值
function getShortestLi(){
var shortest=0;
for(var i=1;i<4;i++){
if($('li').eq(i).height()<$('li').eq(shortest).height()){
shortest=i;
}
}
return shortest;
} function createUrl(num){
return 'http://www.wookmark.com/api/json/popular?page='+num+'&callback=?';
} var bCheck=false;
function getList(n){
$.getJSON(createUrl(n),function(data){
if(data.length==0){
return false;
}else{
for(var i=0;i<data.length;i++){
//console.log(data[i].preview);
var $html=$('<div><img src="'+data[i].preview+'"><p>'+data[i].title+'</p></div>');
$('li').eq(getShortestLi()).append($html); $html.find('img').css('height',(data[i].height*225/data[i].width)+'px');
$html.find('img').css('width','225px');
};
} bCheck=true;
});
} $(function(){
var pageNum=1;
getList(pageNum);
$(window).scroll(function(){ var $li=$('li').eq(getShortestLi());
var scrollTop=document.documentElement.scrollTop||document.body.scrollTop;
//console.log([$li.offset().top+$li.height(),document.documentElement.clientHeight+scrollTop])
//如果li高度与li到页面顶部的高度之和<可视区高度+滚动距离
if($li.offset().top+$li.height()<document.documentElement.clientHeight+scrollTop){
if(bCheck){
bCheck=false;
pageNum++;
//console.log(pageNum);
getList(pageNum);
}else{
return false;
} }
})
})

最后欣赏了下图片,不得不感叹,歪果仁真会玩~

jquery实现简单瀑布流布局的更多相关文章

  1. jquery实现简单瀑布流布局(续):图片懒加载

    # jquery实现简单瀑布流布局(续):图片懒加载 这篇文章是jquery实现简单瀑布流布局思想的小小扩展.代码基于前作的代码继续完善. 图片懒加载就是符合某些条件时才触发图片的加载.最常见的具体表 ...

  2. Ajax+json+jquery实现无限瀑布流布局

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  3. jQuery Wookmark Load 瀑布流布局实例演示

    瀑布流布局非常适合大量图片的展示,一改过去裁剪图片尺寸统一的排版,每张图片都能完全展示,并错落有致,让人眼前一亮. 版本: jQuery v1.4.3+ jQuery Wookmark Load v1 ...

  4. 使用jquery+css实现瀑布流布局

    虽然可以直接使用css实现瀑布流布局,但显示的方式有点问题,所以这儿就直接使用jquery+css来实现瀑布流布局,最终效果如下:      思路是通过将每个小块的position设置为relativ ...

  5. jquery实现简单瀑布流

    瀑布流这个概念一直不是很理解,看到别人可以实现,自己弄了很久还是不能实现就很纠结.瀑布流这根刺就一直扎在我心里,一次偶然的机会看到别人实现了瀑布流,我想我是不是也应该再继续把这个未完成的任务画一个圆满 ...

  6. jquery实现简单瀑布流代码

    测试环境:ie8 ff13.0.1  chrome22 可以将分页获取的内容依次填入四个div中,瀑布流的分页可以以多页(比如5页)为单位二次分页,这样可以减少后台算法的复杂度 <!DOCTYP ...

  7. AJAX+json+jquery实现预加载瀑布流布局

    宽度是一定的高度不定的瀑布流布局 也可以说是无缝拼图 当浏览器滚动到底部时候自动加载图片 加载的图片地址用json 在img.js里 ,还有正在加载动画是用 css3制作的 在ff等支持css3可以显 ...

  8. myWaterfall - jQuery瀑布流布局插件

    myWaterfall - jQuery瀑布流布局插件 Demo http://jsfiddle.net/q3011893/p5k2ogy8/embedded/result,html,css,js/ ...

  9. jQuery Wookmark 瀑布流布局

    瀑布流布局非常适合大量图片的展示,一改过去裁剪图片尺寸统一的排版,每张图片都能完全展示,并错落有致,让人眼前一亮. 版本: jQuery v1.4.3+ jQuery Wookmark Load v1 ...

随机推荐

  1. JSP分页显示实例(基于Bootstrap)

    首先介绍一款简单利落的分页显示利器:bootstrap-paginator 效果截图: GitHub官方下载地址:https://github.com/lyonlai/bootstrap-pagina ...

  2. 【hive】——Hive四种数据导入方式

    Hive的几种常见的数据导入方式这里介绍四种:(1).从本地文件系统中导入数据到Hive表:(2).从HDFS上导入数据到Hive表:(3).从别的表中查询出相应的数据并导入到Hive表中:(4).在 ...

  3. 【mysql】关于悲观锁

    关于mysql中的锁 在并发环境下,有可能会出现脏读(Dirty Read).不可重复读(Unrepeatable Read). 幻读(Phantom Read).更新丢失(Lost update)等 ...

  4. LLVM 笔记(二)—— PHI node

    ilocker:关注 Android 安全(新手) QQ: 2597294287 什么是 PHI node? 所有 LLVM 指令都使用 SSA (Static Single Assignment,静 ...

  5. Cookie无法读取

    问题描述:用谷歌调试可以看到,但是用js去读取的时候,一直提示undefined

  6. 【2016-11-5】【坚持学习】【Day20】【Linq where in 语句】

    今天用到一个where  in  LINQ 语句 IEnumerable<Line> lines = wf.Lines.Where(n => n.RightNode == formR ...

  7. 你不知道的Javascript(上卷)读书笔记之二 ---- 词法作用域

    在前一篇文章中,我们把作用域定义为"管理.维护变量的一套规则",接下来是时候来深入讨论一下Js的作用域问题了,首先我们要知道作用域一般有两种主要的工作类型,一种是词法作用域,一种是 ...

  8. MySQL数据类型-decimal详解

    from:http://www.linuxidc.com/Linux/2013-07/88032.htm 1.首先,对于精度比较高的东西,比如money,我会用decimal类型,不会考虑float, ...

  9. SQLserver中用convert函数转换日期格式

    SQLserver中用convert函数转换日期格式 2008-01-23 15:47 SQLserver中用convert函数转换日期格式2008-01-15 15:51SQLserver中用con ...

  10. redux middleware 的理解

    前言 这几天看了redux middleware的运用与实现原理,写了一个百度搜索的demo,实现了类似redux-thunk和redux-logger中间件的功能. 项目地址:https://git ...