这样的布局并不陌生,从2011年Pinterest创立以来,中国互联网就迅速掀起了一股模仿Pinterest的热潮,国内有众多网站采用瀑布流的布局方式,例如花瓣网、美丽说等等。而事实上在中国互联网,模仿一些在国外被人看好的模式(当然,你也可以说是山寨或抄袭,呵呵!!)向来都是一个不错的idea。
OK,现在进入正题。这里主要介绍瀑布流的一种实现方法:绝对定位(css)+javascript+ajax+json。简单一点如果不做滚动加载的话就是绝对定位(css)+javascript了,ajax和json是滚动加载更多内容的时候用到的。
下面是实现思路:
1、计算页面的宽度,计算出页面可放数据块的列数(如上图所示就有6列)。
2、将各个数据块的高度尺寸记入数组中(需要等所有图片加载完成,否则无法知道图片的高度)。
3、用绝对定位先将页面第一行填满,因为第一行的top位置都是一样的,然后用数组记录每一列的总高度。
4、继续用绝对定位将其他数据块定位在最短的一列的位置之后然后更新该列的高度。
5、当浏览器窗口大小改变时,重新执行一次上面1-4步以重新排放(列数随页面宽度而改变,因而需要重新排放)。
6、滚动条滚动到底部时加载新的数据进来后也是定位在最短的一列的位置之后然后更新该列的高度。
思路有了,然后就是如何用代码实现。当然,如果看完以上的6个步骤你已经知道如何实现,那么下面的内容大可不必细看。
首先在页面上写好基本的HTML和CSS(为方便起见,CSS就不外联了),代码如下:
1 DOCTYPE html>
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <title>瀑布流布局title>
6 <style type="text/css">
7 body{margin:0; font-family:微软雅黑;}
8 #flow-box{margin:10px auto 0 auto; padding:0; position:relative}
9 #flow-box li{
10 width:190px; position:absolute; padding:10px; border:solid 1px #efefef; list-style:none;
11 opacity:0;
12 -moz-opacity:0;
13 filter:alpha(opacity=0);
14 -webkit-transition:opacity 500ms ease-in-out;
15 -moz-transition:opacity 500ms ease-in-out;
16 -o-transition:opaicty 500ms ease-in-out;
17 transition:opaicty 500ms ease-in-out;}
18 #flow-box li img{width:100%;}
19 #flow-box li a{display:block; width:100%; text-align:center; font-size:14px; color:#333; line-height:18px; margin-top:10px; text-decoration:none;}
20 .loadwrap{position:absolute; left:0; width:100%; text-align:center;}
21 style>
22 head>
23 <body>
24 <ul id="flow-box">
25 <li><img src="http://www.mitxiong.com/NewsImages/2012121821504156.jpg" /><a href="#">图片标题1a>li> 26 <li><img src="http://www.mitxiong.com/NewsImages/2012112718241731.jpg" /><a href="#">图片标题2a>li> 27 <li><img src="http://www.mitxiong.com/NewsImages/2012111806582944.jpg" /><a href="#">图片标题3a>li> 28 <li><img src="http://www.mitxiong.com/NewsImages/2012110907231232.jpg" /><a href="#">图片标题4a>li> 29 <li><img src="http://www.mitxiong.com/NewsImages/2012110406319529.jpg" /><a href="#">图片标题5a>li> 30 <li><img src="http://www.mitxiong.com/NewsImages/2012101808066955.jpg" /><a href="#">图片标题6a>li> 31 <li><img src="http://www.mitxiong.com/NewsImages/2012101307276582.jpg" /><a href="#">图片标题7a>li> 32 <li><img src="http://www.mitxiong.com/NewsImages/2012082223432719.jpg" /><a href="#">图片标题8a>li> 33 <li><img src="http://www.mitxiong.com/NewsImages/2012082121509065.jpg" /><a href="#">图片标题9a>li> 34 <li><img src="http://www.mitxiong.com/NewsImages/2012081922387254.jpg" /><a href="#">图片标题10a>li> 35 <li><img src="http://www.mitxiong.com/NewsImages/2012081700252403.jpg" /><a href="#">图片标题11a>li> 36 <li><img src="http://www.mitxiong.com/NewsImages/2012081407597304.jpg" /><a href="#">图片标题12a>li> 37 <li><img src="http://www.mitxiong.com/NewsImages/2012081218248259.jpg" /><a href="#">图片标题13a>li> 38 <li><img src="http://www.mitxiong.com/NewsImages/2012080621278799.jpg" /><a href="#">图片标题14a>li> 39 <li><img src="http://www.mitxiong.com/NewsImages/2012072907484455.jpg" /><a href="#">图片标题15a>li> 40 <li><img src="http://www.mitxiong.com/NewsImages/2012072521564314.jpg" /><a href="#">图片标题16a>li> 41 <li><img src="http://www.mitxiong.com/NewsImages/2012072507238259.jpg" /><a href="#">图片标题17a>li> 42 <li><img src="http://www.mitxiong.com/NewsImages/2012072409035684.jpg" /><a href="#">图片标题18a>li> 43 <li><img src="http://www.mitxiong.com/NewsImages/2012072219405236.jpg" /><a href="#">图片标题19a>li> 44 <li><img src="http://www.mitxiong.com/NewsImages/2012071218416980.jpg" /><a href="#">图片标题20a>li> 45 ul> 46 <div id="loadimg" class="loadwrap"><img src="Images/load.jpg" />div> 47 body> 48 html>
以上代码非常简单,可以看出页面最初将会先加载20个数据块。值得一提的是在CSS里面定义了opacity为0,目的是在数据块未排放好之前先隐藏起来,排放好后再将opacity设为1显示出来,另外这里用了css3的transition做一点体验上的升级;还有一点就是可以看到页面底部有一个id为“loading”的DIV,用来表示数据正在加载中。下面开始用JS实现以上思路(6个步骤)。
1、计算页面的宽度,计算出页面可放数据块的列数
1 <script type="text/javascript">
2 function flow(mh, mv) {//参数mh和mv是定义数据块之间的间距,mh是水平距离,mv是垂直距离
3 var w = document.documentElement.offsetWidth;//计算页面宽度
4 var ul = document.getElementById("flow-box");
5 var li = ul.getElementsByTagName("li");
6 var iw = li[0].offsetWidth + mh;//计算数据块的宽度
7 var c = Math.floor(w / iw);//计算列数
8 ul.style.width = iw * c - mh + "px";//设置ul的宽度至适合便可以利用css定义的margin把所有内容居中
9 }
10 script>
注释写得非常明白,这一步不说应该都很容易懂。
2、将各个数据块的高度尺寸记入数组中
1 <script type="text/javascript">
2 function flow(mh, mv) {//参数mh和mv是定义数据块之间的间距,mh是水平距离,mv是垂直距离
3 //... 省略上一步的部份代码 ...
8 ul.style.width = iw * c - mh + "px";//设置ul的宽度至适合便可以利用css定义的margin把所有内容居中
9
10 var liLen = li.length;
11 var lenArr = [];
12 for (var i = 0; i < liLen; i++) {//遍历每一个数据块将高度记入数组
13 lenArr.push(li[i].offsetHeight);
14 }
15 }
16 script>
由于数据块里面含有图片,也没有给定图片的尺寸,所以需要等待图片加载完成后方可获取其高度;那么可以在window.onload的时候调用flow方法。代码变成:
1 <script type="text/javascript">
2 function flow(mh, mv) {//参数mh和mv是定义数据块之间的间距,mh是水平距离,mv是垂直距离
3 //... 省略上一步的部份代码 ...
8 ul.style.width = iw * c - mh + "px";//设置ul的宽度至适合便可以利用css定义的margin把所有内容居中
9
10 var liLen = li.length;
11 var lenArr = [];
12 for (var i = 0; i < liLen; i++) {//遍历每一个数据块将高度记入数组
13 lenArr.push(li[i].offsetHeight);
14 }
15 }
16 //图片加载完成后执行
17 window.onload = function() {flow(10, 10)};
18 script>
3、用绝对定位先将页面第一行填满,因为第一行的top位置都是一样的,然后用数组记录每一列的总高度。
1 <script type="text/javascript">
2 function flow(mh, mv) {//参数mh和mv是定义数据块之间的间距,mh是水平距离,mv是垂直距离
//... 省略上一步的部份代码 ...
12 for (var i = 0; i < liLen; i++) {//遍历每一个数据块将高度记入数组
13 lenArr.push(li[i].offsetHeight);
14 }
15
16 var oArr = [];
17 for (var i = 0; i < c; i++) {//把第一行排放好,并将每一列的高度记入数据oArr
18 li[i].style.top = "0";
19 li[i].style.left = iw * i + "px";
20 li[i].style.opacity = "1";
21 li[i].style["-moz-opacity"] = "1";
22 li[i].style["filter"] = "alpha(opacity=100)";
23 oArr.push(lenArr[i]);
24 }
25 document.getElementById("loadimg").style.top = _getMaxValue(oArr) + 50 + "px";//将loading移到下面
26 }
27 //图片加载完成后执行
28 window.onload = function() {flow(10, 10)};
29 //获取数字数组的最大值
30 function _getMaxValue(arr) {
31 var a = arr[0];
32 for (var k in arr) {
33 if (arr[k] > a) {
34 a = arr[k];
35 }
36 }
37 return a;
38 }
39 script>
截至目前为止,可以到浏览器里面预览一下效果:
OK,接下来开始放置其他的数据块了,也就是到思路的第4步了。