在 Kayo 的上一篇文章轻图床的新前端与瀑布流布局曾经简略介绍过瀑布流布局,所谓的瀑布流效果就正如轻图床首页效果那样,多个内容相近的栏目紧密排列,尽量使到栏目间的间隙最小(即流体布局),并且随着页面滚动条向下滚动,新的数据会追加至当前页面的尾部直到所有数据加载完毕(滚动触发的 Ajax 翻页)。本文将会介绍如何实现瀑布流布局中的 Ajax 翻页,至于如何实现栏目间的紧密排列,本文将会简略介绍但不在重要的讨论范围。
2013/12/23 更新
轻图床已经全新改版,去掉原有的瀑布流布局,需要参考原有的瀑布流布局效果可以浏览这个另外制作的 Demo(只保留瀑布流翻页和第一张图片的链接,其他的功能入口已经去掉)。
一.实现原理
实现瀑布流布局主要分为两个部分,一是实现流体布局,这里我们采用绝对定位的方式实现,而是滚动触发的 Ajax 分页,这里采用 jQuery 的 Ajax 实现。
第一部分将会采用 Masonry jQuery plugin 。Masonry jQuery plugin 是一款实现流体布局的 jQuery 插件,下文将以轻图床的首页 HTML 为例,给出一个 Masonry 流体布局的实例。第二部分使用 jQuery 的 scroll() 事件触发 Ajax ,触发后使用 jQuery 的 ajax() 方法异步加载新内容,下文将给出完整实例。
二.Masonry 实现的流体布局
假设网站中的 HTML 如下
1 2 3 4 5 6 7 8 9 10 11 | < div id = "content" > <!-- 包含所有图片的容器 --> < div id = "thumbs" > <!-- 各个图片的容器 --> < div class = "imgbox" ></ div > < div class = "imgbox" ></ div > < div class = "imgbox" ></ div > < div class = "imgbox" ></ div > < div class = "imgbox" ></ div > </ div > </ div > |
Masonry 采用绝对定位进行流体布局,因此还需添加如下的一段 css
1 2 | #thumbs { position : relative ; width : 895px ; padding : 10px ; } .imgbox { position : absolute ; } |
则可以在 js 中添加以下一段 jQuery 代码实现流体布局(需先在 head 中添加 jQuery 的库与 Masonry 的插件库, Kayo 测试 jQuery 库为 1.6.2 的版本)
1 2 3 4 5 6 7 8 9 10 11 12 13 | $( function () { // #thumbs 为包含所有图片的容器 var $container = $( '#thumbs' ); // 使用 imagesLoaded() 修复该插件在 chrome 下的问题 $container.imagesLoaded( function (){ $container.masonry({ // 每一列数据的宽度,若所有栏目块的宽度相同,可以不填这段 columnWidth: 279, // .imgbox 为各个图片的容器 itemSelector : '.imgbox' }); }); }); |
这样便实现了网页内容的流体布局,不过这仅仅是第一页的流体布局,下面详细介绍如何获取新一页的内容,最后在文末给出完整的瀑布流布局实例。
三.Ajax 分页实现瀑布流
1.通过 Ajax 的方式获取下一页的内容
我们需要网页中具有如下 HTML 结构的导航, next_link 为下一页的 url。
1 2 3 | < div id = "page_nav" > < a href = "next_link" >下一页</ a > </ div > |
相应的 css
1 | #page_nav { clear : both ; text-align : center ; } |
以下这段代码为通过 Ajax 的方式获取下一页的内容,并追加到当前内容的末尾。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | nextHref = $( "#next_page a" ).attr( "href" ); // 给浏览器窗口绑定 scroll 事件 $(window).bind( "scroll" , function (){ // 判断窗口的滚动条是否接近页面底部 if ( $(document).scrollTop() + $(window).height() > $(document).height() - 10 ) { // 判断下一页链接是否为空 if ( nextHref != undefined ) { // Ajax 翻页 $.ajax( { url: $( "#page_nav a" ).attr( "href" ), type: "POST" , success: function (data) { result = $(data).find( "#thumbs .imgbox" ); nextHref = $(data).find( "#page_nav a" ).attr( "href" ); $( "#page_nav a" ).attr( "href" , nextHref); $( "#thumbs" ).append(result); } }); } else { $( "#page_nav" ).remove(); } } }); |
2.对追加的内容进行流体布局
熟悉 jQuery 的童鞋应该会了解 js 对于通过 Ajax 方式插入到页面中的元素并不起作用,但在这里并不需要作出如使用 live() 等处理,因为 Masonry 已经在内部作出类似的处理并且默认起效,因此只需在 Ajax 成功执行后的回调函数中调用 masonry() 方法即可。
1 2 3 4 | $newElems = $result; $newElems.imagesLoaded( function (){ $container.masonry( 'appended' , $newElems, true ); }); |
3.对 Ajax 翻页过程作出修饰
在上面的过程中已经有完整的瀑布流布局,但是翻页过程中并没有任何提示,而且直接插入多张图片可能会影响用户体验,因此需要对翻页过程作出一些修饰,下面给出完整代码。
这里需要增加一个如下的元素,用于提示正在加载新内容或提示已到了最后一页。
1 2 3 | < div id = "page_loading" > < span >给力加载中……</ span > </ div > |
相应的 css
1 | #page_loading { display : none ; background : #111111 ; opacity : 0.7 ; height : 60px ; width : 220px ; padding : 10px ; position : absolute ; bottom : -50px ; left : 330px ; } |
下面是完整的 Ajax 翻页代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | nextHref = $( "#next_page a" ).attr( "href" ); // 给浏览器窗口绑定 scroll 事件 $(window).bind( "scroll" , function (){ // 判断窗口的滚动条是否接近页面底部 if ( $(document).scrollTop() + $(window).height() > $(document).height() - 10 ) { // 判断下一页链接是否为空 if ( nextHref != undefined ) { // 显示正在加载模块 $( "#page_loading" ).show( "slow" ); // Ajax 翻页 $.ajax( { url: $( "#page_nav a" ).attr( "href" ), type: "POST" , success: function (data) { result = $(data).find( "#thumbs .imgbox" ); nextHref = $(data).find( "#page_nav a" ).attr( "href" ); $( "#page_nav a" ).attr( "href" , nextHref); $( "#thumbs" ).append(result); // 把新的内容设置为透明 $newElems = result.css({ opacity: 0 }); $newElems.imagesLoaded( function (){ $container.masonry( 'appended' , $newElems, true ); // 渐显新的内容 $newElems.animate({ opacity: 1 }); // 隐藏正在加载模块 $( "#page_loading" ).hide( "slow" ); }); } }); } else { $( "#page_loading span" ).text( "木有了噢,最后一页了!" ); $( "#page_loading" ).show( "fast" ); setTimeout( "$('#page_loading').hide()" ,1000); setTimeout( "$('#page_loading').remove()" ,1100); } } }); |
四.备注
本文给出一种完整的瀑布流布局实现方案,其中重点讲述的 Ajax 翻页以一个较为普遍的实例介绍,该代码可以通用于各种站点的 Ajax 翻页,并不局限于瀑布流布局,并且文中主要讲述布局中的 js 部分,关于后台的实现并没有详述。另外该 Ajax 翻页的代码实例并不是轻图床中的代码,因为轻图床中还有切换为手动导航的功能,因此其功能代码比较复杂,有兴趣可以查看轻图床的 js 源码。
5月10日更新
优化瀑布流布局 https://kayosite.com/lighthumbs-transfer-to-sae-and-improve-cascade-layout.html
本文由 Kayo Lee 发表,本文链接:https://kayosite.com/jquery-ajax-turn-page-and-cascade-layout.html
Pingback
评论列表
发现轻图床一个问题,当下拉加载时,前一次加载还正在加载中,用户又不停地下拉,于是中间出现N多空白,我测试的表现为一次性加载我限定个数的N倍
@liypholy 你可以调一下触发加载的条件,原本是滚动条到窗口底部10px时触发加载,调高一点吧!
if( $(document).scrollTop() + $(window).height() > $(document).height() – 10 )
把 10 改大一点试试!
有个BUG.
scroll触发了的时候加个监控,不再发送ajax请求。不然当前情况会多次ajax的。博主自己测测 :D
@Sjolzy 童鞋很细心,谢谢提醒!其实之前我已经发现了这个Bug,写了个解决办法 https://kayosite.com/lighthumbs-transfer-to-sae-and-improve-cascade-layout.html ,看来得在文中提醒一下大家!
请教个问题,如果我想ajax删除某个imgbox,或者进行ajax回复,从而导致imgbox的height变化,我又不想全部reload(那样整个排版可能变化较大),只想所在的单个列微调下,该怎么处理,能否给个思路,谢谢!
@janker 只对一列操作的话很难做到,因为无法直接通过选择器选取一列的imgbox,不妨可以试试只调节当前操作的imgbox,以及该imgbox后面所有的兄弟元素(即对当前正在操作以及后面的imgbox重新调用masonry方法),这样整个排版变化相对较小!
你好,我正在学习瀑布流,看了你的文章后有很大的启发,所以要谢谢你,不过我在学习中发现了个问题不知怎么解决,问题是出在用AJAX获得了新的HTML数据后,用$(data).find(“#page_nav a”).attr(“href”);却获取不到 page_nav 下 a 标签中的 href 中的值,但我在新数据的尾部确实加入了 下一页 用indexOf也能找到,但为什么找不到值
@辉 谢谢你的支持!作为一个博主,我也很高兴我的文章能对读者有所帮助。
不过我不是很明白“在新数据的尾部确实加入了下一页”的意思,能具体再说一下吗?
这里再说明一下:
$(data).find(“#page_nav a”).attr(“href”) 获取的是 Ajax url 里的数据,通常就是下一页页面里的数据,假如我这里是第一页,那么下一页按钮里的链接就是链接到第二页的,如果用 Ajax 翻页,那么就会从按钮里的链接页面(也就是第二页)里获取新的下一页按钮里的链接(也就是第三页的链接),在翻到第二页后再把这个第三页的链接修改到下一页按钮里(因为翻页后只是修改了页面主体内容,因此需要这样修改下一页按钮里的链接),以继续 Ajax 翻页。
瀑布流已成WEB2.0的一种象征,HTML5+CSS3改变了设计大趋势。
@家居服务网 现在的确有很多瀑布流的网页了,HTML5 与 CSS3 会改变 Web 的。
又来找教材了.. :P~~发现masonry的加载有点慢了…
@Kkstxforkamancerman masonry的加载慢不慢得看服务器,不过masonry的执行效率确实不高!
@Kayo 就是再重新定位的执行有点慢~
@Kkstxforkamancerman 是不是获取新一页的时候?
@Kayo 是呀是呀…不能即時定位.
@Kkstxforkamancerman 的确会这样,不过可以改进一下 js ,把定位的时间也算到 loading 上,这样效果应该会好很多!
问下关于后台具体怎么实现呢?
能否提供轻图床的首页那个效果的demo下载呢?
js 对于通过 Ajax 方式插入到页面中的元素并不起作用
有没有解决办法?
@不给力的面条 可以把事件冒泡到 document 上,在回调函数中判断匹配元素,具体的方案谷歌一下是有很多的!
刚才打字 有点乱 发现淘宝那个KISSY.Waterfall 在HTML层面上没有img而全部都是通过ajax获取 这样基本没有SEO可谈 请问他的有办法改进么 不胜感激
能把代码发给我吗?