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. java实现文件变化监控

    一. spring配置文件:application.xml <?xml version="1.0" encoding="UTF-8"?> <b ...

  2. linux中通配符和常用特殊符号

    1 通配符   2 特殊符号 3 参考文档 鸟哥的私房菜 http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_4.php#settings_wildcar ...

  3. IIS+域组策略+hosts:禁止访问指定网站

    一.简介 禁止访问网站可以通过多种方式实现,在网络设备上实现大概是性能最好的方式.本文在域服务器上实现该功能,优点是配置简单.可自定义跳转页面,缺点也很明显,遇到熟悉操作系统的用户,修改hosts文件 ...

  4. jquery选择器demo

    大部分选择器都是基于下面这个简单的页面: <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  5. sass入门

    SASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. SASS 官网介绍: sass is the most mature(成熟的),st ...

  6. c++中static关键字的用法总结

    类中的静态成员真是个让人爱恨交加的特性.我决定好好总结一下静态类成员的知识点,以便自己在以后面试中,在此类问题上不在被动. 静态类成员包括静态数据成员和静态函数成员两部分. 一 静态数据成员: 类体中 ...

  7. [随记]Eval的连接方法

    在 .NET 3.5 及以下版本中,如下做法是错误的: <asp:Label ID="_column" runat="server" Text='栏目 I ...

  8. jquery的各种隐藏显现动画的区别

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="utf-8&quo ...

  9. .gitignore详解

    今天讲讲Git中非常重要的一个文件――.gitignore. https://git-scm.com/docs/gitignore 首先要强调一点,这个文件的完整文件名就是“.gitignore”,注 ...

  10. sql总结(3)---比较全

    一.交叉连接(CROSS JOIN) 交叉连接(CROSS JOIN):有两种,显式的和隐式的,不带ON子句,返回的是两表的乘积,也叫笛卡尔积. 例如:下面的语句1和语句2的结果是相同的. 语句1:隐 ...