若是你常常網上衝浪,這樣良莠不齊的多欄佈局,是否是很眼熟啊? css
相似的佈局,彷佛一晚上之間出如今國內外大大小小的網站上,好比 Pinterest (貌似是最先使用這種佈局的網站了),Mark之,蘑菇街,點點網,以及淘寶最新上線的「哇哦」 等等,卻是很流行哈~ 在淘寶即將上線的衆多產品中,你還會大量看到這樣的形式呢。 html
這種佈局適合於小數據塊,每一個數據塊內容相近且沒有側重。一般,隨着頁面滾動條向下滾動,這種佈局還會不斷加載數據塊並附加至當前尾部。因此,咱們給這樣的佈局起了一個形象的名字 — 瀑布流式佈局。 前端
幾種實現方式
隨着愈來愈多設計師愛用這種佈局,咱們做爲前端,要儘量知足視覺/交互設計師的需求。因此,咱們整理了下這種佈局的幾種實現方式,有三種: css3
1) 傳統多列浮動。即 蘑菇街和哇哦 採用的方式,以下圖所示: git
- 各列固定寬度,而且左浮動;
- 一列中的數據塊爲一組,列中的每一個數據塊依次排列便可;
- 更多數據加載時,須要分別插入到不一樣的列上;
- 線上例子。
優勢: github
- 佈局簡單,應該說沒啥特別的難點;
- 不用明確知道數據塊高度,當數據塊中有圖片時,就不須要指定圖片高度。
缺點: web
- 列數固定,擴展不易,當瀏覽器窗口大小變化時,只能固定的x列,若是要添加一列,很難調整數據塊的排列;
- 滾動加載更多數據時,還要指定插入到第幾列中,仍是不方便。
2) CSS3 定義。W3C 中有講述關於多列布局的文檔,排列出來的樣子: 算法
- 由 chrome/ff 瀏覽器直接渲染出來,能夠指定容器的列個數,列間距,列中間邊框,列寬度來實現;
#container {
-webkit-column-count: 5;
/*-webkit-column-gap: 10px;
-webkit-column-rule: 5px solid #333;
-webkit-column-width: 210px;*/
-moz-column-count: 5;
/*-moz-column-gap: 20px;
-moz-column-rule: 5px solid #333;
-moz-column-width: 210px;*/
column-count: 5;
/*column-gap: 10px;
column-rule: 5px solid #333;
column-width: 210px;*/
}
- column-count 爲列數; column-gap 爲每列間隔距離; column-rule 爲間隔邊線大小; column-width 爲每列寬度; 當只設置 column-width 時,瀏覽器窗口小於一列寬度時,列中內容自動隱藏; 當只設置 column-count 時,平均計算每列寬度,列內內容超出則隱藏; 都設了 column-count 和column-width,瀏覽器會根據 count 計算寬度和 width 比較,取大的那個值做爲每列寬度,而後當窗口縮小時,width 的值爲每列最小寬度。這邊其實很簡單,簡易本身嘗試下,詳細可參考https://developer.mozilla.org/en/CSS3_Columns 中的說明。
- 線上列子。
優勢: chrome
- 直接 CSS 定義,最方便了;
- 擴展方便,直接往容器裏添加內容便可。
缺點: api
- 只有高級瀏覽器中才能使用;
- 還有一個缺點,他的數據塊排列是從上到下排列到必定高度後,再把剩餘元素依次添加到下一列,這個本質上就不同了;
- 鑑於這兩個主要缺點,註定了該方法只能侷限於高端瀏覽器,並且,更適合於文字多欄排列。
3) 絕對定位。即 Pinterest ,Mark之,KISSY 採用的方式:
- 可謂是最優的一種方案,方便添加數據內容,窗口變化,列數/數據塊都會自動調整;
- 線上列子。
缺點:
- 須要實現知道數據塊高度,若是其中包含圖片,須要知道圖片高度;
- JS 動態計算數據塊位置,當窗口縮放頻繁,可能會狂耗性能。
KISSY.Waterfall 實現思路
KISSY 的 Waterfall 組件主要包含兩個部分,一個是對現有數據塊進行排列計算各自所在的位置; 二是下拉滾動時,觸發加載數據操做,並把數據添加到目標容器中。
1) 數據塊排列,算法步驟簡述下:
- 初始化時,對容器中已有數據塊元素進行第一次計算,須要用戶給定: a,容器元素 — 以此獲取容器總寬度; b,列寬度; c,最小列數; 最終列數取的是容器寬度/列寬度和最小列數的最大值,這樣保證了,當窗口很小時,仍然出現最小列數的數據;
- 得到列數後,須要保存每一個列的當前高度,這樣在添加每一個數據塊時,才知道起始高度是多少;
- 依次取容器中的全部數據塊,先尋找當前高度最小的某列,以後根據列序號,肯定數據塊的left,top值,left 爲所在列的序號乘以列寬,top 爲所在列的當前高度,最後更新所在列的當前高度加上這個數據塊元素的高度,至此,插入一個元素結束;
- 當全部元素插入完畢後,調整容器的高度爲各列最大的高度值,結束依次調整;
- 性能效率上的注意點: a,若是當前正在調整中,又觸發了 resize 事件,須要將上次調整暫停後執行此次調整(見 timedChunk 函數); b,resize 觸發會很頻繁,能夠將回調函數緩存一段時候後執行,即當這段時間內屢次觸發了resize事件,但回調函數只會執行一次(見 S.buffer 函數)
- 感興趣的能夠參見源碼。
2) 異步加載數據,前面講的是如何對容器中已有元素進行排列,但不少狀況下,還須要不斷加載新數據塊,爲此專門設計了一個獨立的模塊 KISSY.Waterfall.Loader,其實這個功能就更簡單了,僅包含兩個步驟:
- 綁定滾動事件,並肯定預加載線高度值,即滾動到哪一個高度後,須要去加載數據,其實這個就是列的最小高度值,這樣當前滾動值和最小高度值比較一下便可判斷出來,是否要觸發加載數據;
- 加載數據,爲了避免對數據源作太多限制,徹底由使用者本身決定數據源從哪邊獲取和其格式,這樣更好的方便用戶使用。爲此,該組件只提供一個load(success,end) 接口,怎樣load 由用戶本身去定義,而其中的 success/end,分別給出如何添加新數據(suceess 即同 addItems)/如何中止加載的接口。這樣真是太方便了~~
- 感興趣的能夠參見源碼。
KISSY。Waterfall 示例和文檔
看到這邊,是否是很想試用一下~~ 嗯嗯,這裏給出一些相關學習資料和示例,以供參考:
歡迎試用和提出意見~~
來源:http://ued.taobao.com/blog/2011/09/14/waterfall/