1. 程式人生 > >例項解釋瀑布流圖的實現原理與方法

例項解釋瀑布流圖的實現原理與方法

今天博主上網搜了一下關於瀑布流圖的文章,發現實現瀑布流圖的方法大概有“通過JS排版”與“通過後臺排版”兩種。博主認為“通過JS排版”是一種更好的方法,而且網上也是普遍這麼認為的。所以博主先簡單介紹一下“通過後臺排版”的原理,然後在詳細說說“通過JS排版”的原理以及實現過程。


原理
通過後臺排版:



 
如圖,不知道你們看不看得懂……原理就是通過CSS設定出N個縱向的框來,然後在後臺輸出網頁之前,將元素逐個的加到最短的框中去,或者是先填滿第一列,在依次填滿後面的列,最後輸出網頁的時候,就是排好版的瀑布流圖了!


這種方法將排版的工作交給了網站後臺,使用者接收到的網頁就是排好版的,客戶端壓力極少,但是因為對網頁的排版計算全部交由後臺,網頁開啟之前的空白時間相應增加,很有可能讓使用者失去開啟網頁的興趣。


通過JS排版:
如果通過JS排版的話,博主的方法就是先計算出瀑布流圖中元素應當出現的位置,然後通過絕對定位來講元素放置到相應的位置去。


原理很簡單吧?:》


實現
<div id="s_waterFall">
<span style="white-space:pre">	</span><div class="waterDiv">
<span style="white-space:pre">		</span><!-- HTML content -->
<span style="white-space:pre">	</span></div>
<span style="white-space:pre">	</span><div class="waterDiv">
<span style="white-space:pre">		</span><!-- HTML content -->
<span style="white-space:pre">	</span></div>
    <span style="white-space:pre">	</span><div class="waterDiv">
<span style="white-space:pre">		</span><!-- HTML content -->
<span style="white-space:pre">	</span></div>
    <span style="white-space:pre">	</span><div class="waterDiv">
<span style="white-space:pre">		</span><!-- HTML content -->
<span style="white-space:pre">	</span></div>
    <span style="white-space:pre">	</span><div class="waterDiv">
<span style="white-space:pre">		</span><!-- HTML content -->
<span style="white-space:pre">	</span></div><span style="white-space:pre">	</span><div class="waterDiv">
<span style="white-space:pre">		</span><!-- HTML content -->
<span style="white-space:pre">	</span></div>
</div>


HTML結構如上,JS定位的只是.waterDiv元素們,而.waterDiv元素的內容是可以隨意設定的。

就像下面這樣:

<div id="s_waterFall">
	<div class="waterDiv">
		<span>hello</span>
	</div>
	<div class="waterDiv">
		<a href="#">
			<img src="images/2.png" />
			<span>hello</span>
	    </a>
	</div>
	<div class="waterDiv">
		<a href="#">
            <img src="images/3.png" />
		</a>
		<span>hello</span>
	</div>
	<div class="waterDiv">
		<!—HTML Code -->
	</div>
</div>


而因為.waterDiv元素們是通過position:absolute來絕對定位的,所以#s_waterFall在CSS中的position屬性就一定要設定為absolute、relative或fixed三個中的一個,至於為什麼在CSS Image Map那篇文章中有介紹,這裡就不贅述了。


這裡我們設定position為relative,這與static(預設值)效果是一樣的,並且可以約束內部絕對定位的元素。


#s_waterFall{
width:1300px; /* 寬度 */
margin:100px auto;/* 居中 */
position:relative;
}


然後我們設定.waterDiv的屬性:

.waterDiv{
width:230px; /* 每一列的寬度 */
box-shadow:-3px 3px 5px #111;/* 視覺效果 */
border:solid #999 1px;/* 視覺效果 */
position:absolute;/* 設定為絕對定位 */
}


接下來就是JS程式碼了!


首先我們要將JS程式碼放在一個自動執行的匿名函式中:
(function(){
/* JavaScript Code */
}())


很多插架甚至框架都是這麼做的,這樣做的好處有很多,其中一個好處就是我們的變數什麼的不會汙染別人程式碼或外掛的名稱空間。其他的我會在以後再寫一篇文章來說,這裡就不贅述了。


這個外掛現在是可以設定父元素的寬度(total_width),列數(col_num),列寬(col_width),瀑布流子元素的類名稱(kid_class),兩個子元素之間的間距(margin_vertical)。一開始直接寫死為四列的。可能用現在這個版本來介紹的話會比較難理解,但是一開始的版本我忘了儲存……所以就直接拿這個來說吧:》


在JS程式碼中一個好習慣是在函式作用域中把用到的變數在作用域頭部全部宣告一遍。所以我們先生命變數:

/* config area start*/
var total_width = 1300;
//瀑布流圖父元素的寬度,用來計算列之間距離,不是設定父元素寬度
var col_num = 4;//設定列數
var col_width = 230;//設定列寬
var kid_class = "waterDiv";//設定瀑布流圖子元素的類名
var margin_vertical = 20;//設定瀑布流圖子元素的垂直間距
/* config area end*/

/* ↑ for users ↑ */
/* check start */
if( col_num * col_width > total_width){
//如果列數過多,影響顯示效果,會在console中提醒
console.log("Warning : Father div is too small !!!!"); 
}

/* check end */

/* variables start */
var col_heights = new Array(col_num);//生成用來記錄當前列長度的陣列
for(i = 0; i < col_heights.length; i++){ //將陣列元素值置為0
col_heights[i] = 0;
}
var min_col = 0;//遍歷時,當前長度最小的列在陣列中的的索引值
var top_int = 0;//遍歷時,當前元素應設定的絕對定位top值
var left_int = 0;//遍歷時,當前元素應設定的絕對定位left值
var i; //for迴圈計數變數
var str = ""; //空的字串變數
var margin_horizontal = ( total_width - col_num * col_width ) / ( col_num * 2 );
//自動計算列之間距離
/* variables end*/


然後我們遍歷所有的.waterDiv元素,當遍歷到某個元素時,先找出目前最短的一列,這就是我們要新增元素的一列,然後我們計算出該元素絕對定位的top與left值,賦給該元素,這樣在視覺上,該元素就附加在了最短的一列上了,最後不要忘了更新該列的當前長度啊!


$("." + kid_class).each(function(){ //遍歷所有.waterDiv並設定top與left值
min_col = minOfArray(col_heights);//獲取當前長度最小的列的索引值
top_int = col_heights[min_col];//當前元素應設定的絕對定位top值


left_int = margin_horizontal + ( col_width + margin_horizontal * 2 ) * min_col;//計算當前元素應設定的絕對定位left值


$(this).css("top", top_int + "px");//對top, left進行設定
$(this).css("left", left_int + "px");//"px"不要忘記加啊!
col_heights[min_col] += $(this).height() + margin_vertical;//更新列的長度
});

function minOfArray(col_array){
//這是一個找出陣列中最小的元素,並返回該元素索引的函式,就是在上一段程式碼中呼叫的。
/* 
* input : Array of numbers
* output: the index of minimal number.
*/
var min_num = col_array[0];
var min_index = 0;
for(var i = 0; i < col_array.length; i++){
if(col_array[i] < min_num){
min_num = col_array[i];
min_index = i;
}
}

return min_index;
}


這樣,開啟網頁,一個瀑布流圖的demo就做好了!如果不能執行,檢查一下是不是忘了引用jQuery庫了?:》