網(wǎng)頁(yè)設(shè)計(jì)瀑布流式布局的JavaScript實(shí)現(xiàn)方式
瀑布式布局是一種多列等寬不等高的一種頁(yè)面展示方式,用于圖片來(lái)源比較復(fù)雜,圖片尺寸比較復(fù)雜時(shí)可以使用的一種展示方式,這種展示方式比較優(yōu)美,讓人有種錯(cuò)落有致的感覺.這種展示方式在淘寶的我要買,新浪微博的廣場(chǎng)以及蘑菇街等等網(wǎng)站都有應(yīng)用
實(shí)現(xiàn)布局有三個(gè)思路:
- 最傳統(tǒng)的思路,多弄幾個(gè)容器,分幾列,然后往每個(gè)列里面插入元素.其實(shí)用table分幾列實(shí)現(xiàn)更加方便:P;
- 使用html5中css3的多列布局來(lái)實(shí)現(xiàn).參見w3c標(biāo)準(zhǔn)中的css3多列布局模塊;
- 使用絕對(duì)布局,通過javascript生成元素的布局位置.
前兩種方法在網(wǎng)上都有比較詳細(xì)的介紹,我這里就不再多說(shuō)了,這里主要說(shuō)一下我做的第三種實(shí)現(xiàn)的優(yōu)缺點(diǎn)以及我的實(shí)現(xiàn)思路.
第三種方案是所有的要布局的元素都是絕對(duì)定位的,然后通過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í)候是通過使用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)元素高地差距過大的情況.看一下新浪weibo的廣場(chǎng)圖片效果:
可以看到越到最后可能列高度之間的差距會(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)擊下載:
下載信息 [文件大?。?04.83 KB 下載次數(shù): 次] |
點(diǎn)擊下載文件:wate-layout |
本文地址:http://m.likemindfilms.com/tutorial/di1011.html
您可能還喜歡
- Macaron 馬卡龍系色譜 ;附HC(16進(jìn)制碼
- 7個(gè)手機(jī)版網(wǎng)頁(yè)設(shè)計(jì)的原則
- 折紙多邊形網(wǎng)頁(yè)背景效果制作教程
- 龐門正道:好好玩耍的點(diǎn)線面(上)
- 網(wǎng)頁(yè)設(shè)計(jì)中的常見頁(yè)面布局方式
- WAP APP的柵格設(shè)計(jì)
- 八種很漂亮的排版方法和技巧分享
- 網(wǎng)頁(yè)設(shè)計(jì)的首屏標(biāo)準(zhǔn)你了解多少?
- 字體大寶庫(kù):40款為網(wǎng)頁(yè)設(shè)計(jì)師準(zhǔn)備的時(shí)
- 視覺設(shè)計(jì)分享—專題頁(yè)面設(shè)計(jì)篇
- 專訪:石墨文檔產(chǎn)品總監(jiān)羅穎
- UI設(shè)計(jì)不得不知的移動(dòng)端UI尺寸適
- 光音移動(dòng)設(shè)計(jì)規(guī)范 — 表單類
- 體驗(yàn)設(shè)計(jì)中的排序問題
- 網(wǎng)頁(yè)設(shè)計(jì)精粹 網(wǎng)頁(yè)中那些迷人的按
- aliued:響應(yīng)式設(shè)計(jì)的現(xiàn)狀與趨勢(shì)
- 10個(gè)智能對(duì)象處理的ps技巧
- 網(wǎng)頁(yè)UI - 原子設(shè)計(jì)理論(上)
- 如何通過設(shè)計(jì)提升banner點(diǎn)擊率?
- 晉小彥視覺設(shè)計(jì)系列文章(二):全屏