jQuery實現簡單瀑布流佈局

WaterFull

最近正在實習,痛苦的實習日子,不過學到了超多。。。。
前幾天剛好在做網頁的瀑布流佈局,本來使用的是masonry.js插件,但倒黴的是這個插件對jQuery版本有所限制,公司模板使用的是2.1.0,然而mosonry並不理會這的版本的jQuery,任性的很。。無奈之下,用高版本jQuery進行替換,結果不幸的是,另一小夥伴在該項目中使用的另一個插件開始報錯,估計是嫌這個jQuery版本太高。。。好的吧,都難伺候,不如自己來寫一個
昨天老闆檢查說不行,他需要用瀑布流佈局,並同時每個item順序不能改變。。好吧,還要改,不過這個版本的還是想在博客中記錄下來^^

先放成果圖:
無順序而言的瀑布流

原理:先將容器div的position要設置爲relation,之後的每個item個都將以absolute的形式安放在容器中,這樣的話item的位置就可以輕鬆用top和left安放。我這個例子中,每個item都是等寬的,這樣難度係數又下降了很多(哈哈。。不等寬的有機會再去實現吧)。安放分兩種,第一種是第一行的那些item,他們top都直接設爲0就好,left則是他們的個數乘以他們的寬度;第二種是除去第一行的其他行,他們則是先去找數組中的最小高度(數組:放置每一列此時的高度),top就是那最小高度,而left則是數組下標(也就是第幾列(0,1,2…))

HTML代碼:

<div id="grid">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    ...
</div>

CSS代碼:
(css代碼並不全,這要看個人所寫內容決定了,不過重要的都在下面了)

#grid {
    position: relative;
}
.item {
    position: absolute;
    left: 0;
    top: 0;
    width: 280px;
    height: auto;
    overflow: hidden;
    padding: 15px;
}

jQuery代碼:

function itemWaterfull() {
    var margin = 0;  //每個item的外邊距,因人需求而定
    var items = $(".item");  //每個item的統一類名
    var item_width = items[0].offsetWidth + margin; //取區塊的實際寬度
    $("#grid").css("padding", "0");  //容器的起始內邊距先設爲0,按之後一行item的寬度再來設,保證所有item的居中
    var container_width = $("#grid")[0].offsetWidth; //獲取容器寬度
    var n = parseInt(container_width / item_width);  //一行所允許放置的item個數
    var container_padding = (container_width - (n * item_width)) / 2; //一行寬度在容器中所剩餘的寬度,設爲容器的左右內邊距
    $("#grid").css("padding", "0 " + container_padding + "px");
    //尋找數組最小高度的下標
    function findMinIndex(arr) {
        var len = arr.length, min = 999999, index = -1;
        for(var i = 0; i < len; i++) {
            if(min > arr[i]) {
                min = arr[i];
                index = i;
            }
        }
        return index;
    }
    //放置item
    function putItem() {
        var items_height = [];  //每個item的高度
        var len = items.length;  //獲取item的個數
        for(var i = 0; i < len; i++) {
            var item_height = items[i].offsetHeight;  //獲取每個item的高度
            //放置在第一行的item
            if(i < n) {
                items_height[i] = item_height;  //高度數組更新
                items.eq(i).css("top", 0);
                items.eq(i).css("left", i * item_width);

            } else {  //放置在其他行的item        
                var min_index = findMinIndex(items_height);  //尋找最小高度
                if(min_index == -1) {
                    console.log("高度計算出現錯誤");
                    return ;
                }
                items.eq(i).css("top", items_height[min_index] + margin);
                items.eq(i).css("left", min_index * item_width);
                items_height[min_index] += item_height + margin;  //高度數組更新
            }
        }

        var max_height = Math.max.apply(null, items_height);
        $("#grid").css("height", max_height);   //最後更新容器高度
    }

    putItem();
}
itemWaterfull();
window.onresize = function() {itemWaterfull();}; //在窗口大小改變後,item重新放置

上面代碼有個問題,截圖如下:
最後一行的尷尬
在最後一行時,若佈局仍按則高度最小的安放,就會是佈局很難看。所以將最後一行按順序放置就好了^ ^
將 jQuery 中的 putItem() 完善,如下:

function putItem() {
    var items_height = [];  //每個item的高度
    var len = items.length;  //獲取item的個數
    for(var i = 0; i < len; i++) {
        var item_height = items[i].offsetHeight;  //獲取每個item的高度
        //放置在第一行的item
        if(i < n) {
            items_height[i] = item_height;  //高度數組更新
            items.eq(i).css("top", 0);
            items.eq(i).css("left", i * item_width);

        } else {  //放置在其他行的item  
            var final_row_fir = parseInt(len / n) * n; //最後一行第一個item的下標
            //處於最後一行
            if(final_row_fir <= i) {
                var index = i - final_row_fir;  //該item所應該放置的列
                items.eq(i).css("top", items_height[index] + margin);
                items.eq(i).css("left", index * item_width);
                items_height[index] += item_height + margin;
            } else {      
                var min_index = findMinIndex(items_height);  //尋找最小高度
                if(min_index == -1) {
                    console.log("高度計算出現錯誤");
                    return ;
                }
                items.eq(i).css("top", items_height[min_index] + margin);
                items.eq(i).css("left", min_index * item_width);
                items_height[min_index] += item_height + margin;  //高度數組更新
            }
        }
    }
    var max_height = Math.max.apply(null, items_height);
    $("#grid").css("height", max_height);   //最後更新容器高度
}

完善後的結果圖:
特殊處理的最後一行

其實最後想想,若想實現瀑布流佈局,那麼第幾行這種概念就不應該存在,所以完善後的代碼,在一面只有寥寥幾行是還是可以的,多了恐怕會有事故發生。。。現在網頁瀑布流的存在形式比較多的是可以下拉後動態加載,不過這也面臨着瀏覽器緩存過大,頁面加載過慢的問題,所以用幾行形式的瀑布流加上分頁其實也是不錯的選擇。。。

以上所有僅是個人見解,希望大家可以多多指教 ^ ^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章