瀑布流布局淺析
簡介
如果你經常網上沖浪,這樣參差不齊的多欄布局,是不是很眼熟啊?
類似的布局,似乎一夜之間出現在國内外大大小小的網站上,比如 Pinterest (貌似是最早使用這種布局的網站了),Mark之,蘑菇街,點點網,以及淘寶最新上線的“哇哦” 等等,倒是很流行哈~ 在淘寶即将上線的衆多産品中,你還會大量看到這樣的形式呢。
這種布局适合于小資料塊,每個資料塊内容相近且沒有側重。通常,随着頁面滾動條向下滾動,這種布局還會不斷加載資料塊并附加至目前尾部。是以,我們給這樣的布局起了一個形象的名字 — 瀑布流式布局。
幾種實作方式
随着越來越多設計師愛用這種布局,我們作為前端,要盡可能滿足視覺/互動設計師的需求。是以,我們整理了下這種布局的幾種實作方式,有三種:
1) 傳統多列浮動。即 蘑菇街和哇哦 采用的方式,如下圖所示:
- 各列固定寬度,并且左浮動;
- 一列中的資料塊為一組,列中的每個資料塊依次排列即可;
- 更多資料加載時,需要分别插入到不同的列上;
- 線上例子。
優點:
- 布局簡單,應該說沒啥特别的難點;
- 不用明确知道資料塊高度,當資料塊中有圖檔時,就不需要指定圖檔高度。
缺點:
- 列數固定,擴充不易,當浏覽器視窗大小變化時,隻能固定的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 中的說明。
- 直接 CSS 定義,最友善了;
- 擴充友善,直接往容器裡添加内容即可。
- 隻有進階浏覽器中才能使用;
- 還有一個缺點,他的資料塊排列是從上到下排列到一定高度後,再把剩餘元素依次添加到下一列,這個本質上就不一樣了;
- 鑒于這兩個主要缺點,注定了該方法隻能局限于高端浏覽器,而且,更适合于文字多欄排列。
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 示例和文檔
看到這邊,是不是很想試用一下~~ 嗯嗯,這裡給出一些相關學習資料和示例,以供參考:
- Waterfall API 文檔,相關構造器,配置項,方法都在這裡;
- 示例,包含靜态和動态兩種。