您當前位置:圖趣網(wǎng)(Tuquu) >> 網(wǎng)頁設(shè)計教程 >> 設(shè)計理論 >> 瀏覽設(shè)計教程

網(wǎng)頁設(shè)計瀑布流式布局的JavaScript實現(xiàn)方式

瀑布式布局是一種多列等寬不等高的一種頁面展示方式,用于圖片來源比較復雜,圖片尺寸比較復雜時可以使用的一種展示方式,這種展示方式比較優(yōu)美,讓人有種錯落有致的感覺.這種展示方式在淘寶的我要買,新浪微博的廣場以及蘑菇街等等網(wǎng)站都有應(yīng)用

實現(xiàn)布局有三個思路:

  1. 最傳統(tǒng)的思路,多弄幾個容器,分幾列,然后往每個列里面插入元素.其實用table分幾列實現(xiàn)更加方便:P;
  2. 使用html5中css3的多列布局來實現(xiàn).參見w3c標準中的css3多列布局模塊;
  3. 使用絕對布局,通過javascript生成元素的布局位置.

前兩種方法在網(wǎng)上都有比較詳細的介紹,我這里就不再多說了,這里主要說一下我做的第三種實現(xiàn)的優(yōu)缺點以及我的實現(xiàn)思路.

第三種方案是所有的要布局的元素都是絕對定位的,然后通過javascript來判斷每個元素位置,動態(tài)設(shè)置位置實現(xiàn)布局.

缺點

需要使用javascript來遍歷元素,然后要根據(jù)前一個元素來判斷后一個元素的位置,這樣可能對一些老版本的瀏覽器造成負擔,特別是IE6這種 老古董,而且在javascript失效的時候,整個頁面的布局都會亂掉.另外如果整個頁面寬度是變化的,則可能每次窗口尺寸改變時都要重新計算所有元素 的位置,在頁面中元素較多的時候可能會有閃爍的現(xiàn)象.另外如果頁面中出現(xiàn)圖片,則需要實現(xiàn)定義好圖片的尺寸,否則會出現(xiàn)無法正確計算元素位置的情況.

優(yōu)點

布局更加靈活,元素絕對定位,可以使用javascript靈活操作.頁面寬度改變時可以重新布局整個頁面.可以使頁面的中的元素真正流動起來,讓新添加的元素插入到高度最低的列,使頁面的低端更加整齊,對插入的元素高地要求較低.可以較為方便的實現(xiàn)延遲加載.

具體實現(xiàn)

最開始我實現(xiàn)的時候是通過使用javascript生成虛擬的列,根據(jù)元素的順序為每個元素分配一個列和行,然后計算每個元素的位置,舉個例子,現(xiàn)在假設(shè)有四個列:

使其在頁面中布局.事實上這個解決辦法跟第一種和第二種是一個道理的.最后頁面每列的高度差別可能會很大.

//getElements()方法用于獲取頁面中的元素
var items = getElements();
var columnCount = 4;
var columnWidth = 230;
var padding = 8;
//遍歷所有元素
for(var i = 0, len = items.length; i < len; i++){
	//獲取當前的元素
	var currentItem = items[i];
	//獲取當前對象的列
	var currentColumn = (i + 1) % 4;
	//獲取當前對象的行
	var currentLevel = parseInt(i / 4);

	//有了當前的行跟列可以根據(jù)上一層的對象計算出當前對象的高度
	var left = currentColumn * columnWidth;
	var top = items[i - 4] ? 0 : items[i - 4].style.top + items[i - 4].clientHeight + padding;
	//設(shè)置當前的位置
	currentItem.style.top = top + 'px';
	currentItem.style.left = left + 'px';
}

代碼和邏輯都比較簡單,根據(jù)當前的行跟列計算出位置就行了.但是這個邏輯還是會出現(xiàn)元素高地差距過大的情況.看一下新浪weibo的廣場圖片效果:

新浪weibo廣超圖片列表效果圖

 

可以看到越到最后可能列高度之間的差距會越大.這不是我們想要實現(xiàn)的效果.

所以我這里換了一個思路,虛擬的列還是要有的,但是行的概念我們拋棄掉,我采用的是一個類似流動的概念,新插入的元素是根據(jù)每個列的高度,那個高度 最低就流向哪個列,最后確保每個列的高度都趨近一致,實現(xiàn)我們想要的效果.當然我們可以采取獲取所有元素的高度,然后統(tǒng)一計算一下,獲取一個最佳的排列方 法,但是這會給瀏覽器帶來較大的計算量,而且如果不斷的加載更多的圖片我們會得不償失,所以我們采用的是一個流動的模型,只讓當前對象尋找最低的高度然后 插入.

這里我實現(xiàn)了一個Column對象,一個ImgItem對象.Column對象用于維護每一列的信息,包括列的最到高度列寬度等列信息.ImgItem對象保存了一個html節(jié)點對象,還有一些設(shè)置元素位置,獲取當前元素位置的方法.

下面是Column對象的代碼:

var Column = function(order){
	this.order = order;
	this.maxHeight = 0;
	this.columnWidth = 230;
	this.left = this.columnWidth * order;
	this.lastItem = null;
	this.positioned = false;
	this.setReferItem = function(item){
		this.lastItem = item;
	}

	this.getHeight = function(){
		if(this.lastItem){
			this.maxHeight = this.lastItem.getBottom();
		}
		return this.maxHeight;
	}

	this.getLeft = function(){
		return this.left;
	}
};

ImgItem對象的代碼:

var ImgItem = function(referNode, column){
	this.referNode = referNode;
	this.bottom = -1;
	this.positioned = false;
};

ImgItem.prototype = {
	/*
	 *set the refer node's top
	 * @param value: Number
	 */
	setTop: function(value){
		this.referNode.style.top = value + 'px';
	},
	/*
	 *set the refer node's left
	 * @param value: Number
	 */
	setLeft: function(value){
		this.referNode.style.left = value + 'px';
	},
	/*
	 *get the refer node bottom position
	 */
	getBottom: function(){
		if(this.positioned){
			if(this.bottom < 0){
				this.bottom = parseInt(this.referNode.style.top) + this.referNode.clientHeight;
			}
			return this.bottom;
		}else{
			throw("current node has not been positioned!");
		}
	},
	setPosition: function(column){
		this.positioned = true;
		this.setLeft(column.getLeft());
		this.setTop(column.getHeight() + 10);
		column.setReferItem(this);
	}
};

基礎(chǔ)打好了,下面要做的就是給元素進行布局了:

//首先根據(jù)配置信息中的列數(shù)初始化列
for(var i = 0, len = this.config.columnCount; i < len; i++){
	this.columns.push(new Column(i));
}
//獲取頁面上已存在的對象
var liItems = document.getElementById('img_list').getElementsByTagName('li');
//將所有的對象進行布局
for(i = 0, len = liItems.length; i < len; i++){
	this.addNewItem(liItems[i]);
}

好吧這里還用到了一個addNewItem方法:

getMinHeightColumn: function(){
	var minHeight = -1, tempColumn = null;
	//遍歷所有的列,獲取當前高度最低的列,并返回
	for(var i = 0,len = this.columns.length; i < len; i++){ 		if(minHeight > this.columns[i].getHeight() || minHeight == -1){
			minHeight = this.columns[i].getHeight();
			tempColumn = this.columns[i];
		}
	}

	return tempColumn;
},

getMaxHeight: function(){
	var maxHeight = -1;
	//遍歷列對象,獲取高度最高的列并返回高度
	for(var i = 0, len = this.columns.length; i < len; i++){
		if(maxHeight < this.columns[i].getHeight()){
			maxHeight = this.columns[i].getHeight();
		}
	}

	return maxHeight;
},
addNewItem: function(liItem){
	//設(shè)置元素的位置
	var imgItem = new ImgItem(liItem);
	imgItem.setPosition(this.getMinHeightColumn());
	this.cachedItems.push();
	//設(shè)置容器的高度
	document.getElementById('img_list').style.height = this.getMaxHeight() + 'px';
}

基本的布局邏輯已經(jīng)都齊了,還有的就是lazyload的一些邏輯了,這些邏輯都比較通用.加載后布局對象的邏輯是相同的.這里就不再贅述了.

點擊下載:

 下載信息  [文件大小:104.83 KB 下載次數(shù): 次]
點擊下載文件:wate-layout

 


 

[教程作者:admin]
免責聲明:本站文章系圖趣網(wǎng)整理發(fā)布,如需轉(zhuǎn)載,請注明出處,素材資料僅供個人學習與參考,請勿用于商業(yè)用途!
本文地址:http://m.likemindfilms.com/tutorial/di1011.html
讓網(wǎng)頁設(shè)計變得很糟糕的十大元兇
回顧2011 專家眼中的網(wǎng)站設(shè)計
圖趣網(wǎng)微信
建議反饋
×