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

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

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

實(shí)現(xiàn)布局有三個(gè)思路:

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

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

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

缺點(diǎn)

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

優(yōu)點(diǎn)

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

具體實(shí)現(xiàn)

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

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

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

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

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

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

 

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

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

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

下面是Column對(duì)象的代碼:

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對(duì)象的代碼:

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ìn)行布局了:

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

好吧這里還用到了一個(gè)addNewItem方法:

getMinHeightColumn: function(){
	var minHeight = -1, tempColumn = null;
	//遍歷所有的列,獲取當(dāng)前高度最低的列,并返回
	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;
	//遍歷列對(duì)象,獲取高度最高的列并返回高度
	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的一些邏輯了,這些邏輯都比較通用.加載后布局對(duì)象的邏輯是相同的.這里就不再贅述了.

點(diǎn)擊下載:

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

 


 

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