天天看點

簡單瀑布流小插件(寬度一定)

瀑布流這個東西,學過很久了,現在把它記錄一下。

簡單說一下原理:定義一個數組儲存第一行中的所有div的高度(如果有間隙,加上間隙),找出第一行中的最小高度,然後下一行第一個div的top值就等于這個最小高度,然後更新儲存的最小高度,繼續重複執行。

如果我們要将它做成小插件的話,需要考慮:

1. 我們要将它放到什麼地方去?

2. 目前顯示的是第幾頁

3. 每頁顯示多少數量

4. jsonp傳回的資料

5. 每個div的寬度

6. div與div之間的間隙

7. 傳入進來的圖檔的key值

8. 如果有文字說明,傳入進來的文本的key值

以上幾點都是我們要考慮的,因為這些可能是會變化的,是以這些都要做成變量,讓使用者傳入。

好了,以下附上源碼(還有點小問題,但我還不知哪裡出問題了)。

/**
 * 瀑布流
 * @param {Object} json:資料
 */
function WaterFall(json){
    this.obj = json.obj;                // 瀑布流要在哪個對象中顯示
    this.page = json.page || ;         // 目前的頁數,預設為1
    this.count = json.count || ;      // 每頁顯示的資料量,預設為10
    this.data = json.data;              // 利用jsonp擷取的資料
    this.width = json.width;            // 每張圖檔的寬度
    this.gap = json.gap;                // 圖檔與圖檔之間的間隙
    this.path = json.path;              // 利用jsonp傳回的資料中的圖檔路徑的key值,不是value值
    this.textName = json.textName;      // 文本描述,如果沒有文本,可以不寫或者傳入可以轉換為false的值

    this.arrHeight = [];                // 記錄一行中每個div高度的數組
    this.divs = [];                     // 裝着産生的div
    this.num = this.page * this.count;  // 目前顯示的圖檔的總數
    this.isEnd = false;                 // 是否到了利用jsonp擷取的最後一個資料,如果到了,就算繼續滾動滑鼠滾輪,也不會再加載任何資料
}
// 初始化方法
WaterFall.prototype.init = function(){
    this.setObj();
    this.createElements();
    this.updatePosition();
    this.mouseEnd();
};
// 主要用于設定傳入進來的對象的position屬性
WaterFall.prototype.setObj = function(){
    this.obj.style.position = 'relative';
};
// 擷取最小高度
WaterFall.prototype.getMinHeight = function(){
    var min = ;
    for(var i = , len = this.arrHeight.length; i < len; i ++){
        if(this.arrHeight[i] < this.arrHeight[min]){
            min = i;
        }
    }
    return min;
};
// 擷取最大高度
WaterFall.prototype.getMaxHeight = function(){
    var max = ;
    for(var i = , len = this.arrHeight.length; i < len; i ++){
        if(this.arrHeight[i] > this.arrHeight[max]){
            max = i;
        }
    }
    return max;
};
// 建立div、建立img
WaterFall.prototype.createElements = function(){
    var start = this.count * (this.page - ); // 目前已經顯示了多少資料
    for(var i = start; i < this.num; i ++){
        var div = document.createElement('div');
        div.style.width = this.width + 'px';
        div.style.margin = this.gap/ + 'px';
        div.style.position = 'absolute';

        var img = document.createElement('img');
        img.src = this.data[i][this.path];
        img.style.width = this.width + 'px';

        div.appendChild(img);

        // 如果有傳入文本,則建立p标簽
        if(this.textName){
            var p = document.createElement('p');
            p.innerHTML = this.data[i][this.textName];

            div.appendChild(p);
        }

        this.divs.push(div);
    }
};
// 更新div的位置
WaterFall.prototype.updatePosition = function(){
    // 計算一行能放多少個div
    var cols = parseInt(this.obj.offsetWidth / (this.width + this.gap));
    // 計算更新位置的起始值(上一次的結束位置)
    var start = this.count * (this.page - ); // 目前已經顯示了多少資料

    for(var i = start; i < this.num; i ++){
        var d = this.divs[i];
        this.obj.appendChild(d); // 将建立的div添加到對象中
        if(i < cols){ // 計算并設定第一行的div的left
            d.style.top = ;
            d.style.left = i * (this.width + this.gap) + 'px';
            // 将第一行中每個div的(高度+間隙)添加到數組中
            this.arrHeight.push(d.offsetHeight + this.gap);
        }else{
            var min = this.getMinHeight(); // 獲得每一行中的最小高度的div的下标
            d.style.top = this.arrHeight[min] + 'px';
            d.style.left = min * (this.width + this.gap) + 'px';

            // 更新數組中儲存的最小高度,上一行的最小高度加上目前div的高度及間隙
            this.arrHeight[min] += (d.offsetHeight + this.gap);
        }
    }
    // 設定最外層obj的高度值
    var max = this.getMaxHeight();
    this.obj.style.height = this.arrHeight[max] + 'px';

};
// 滑鼠滾動到底部時,頁數加1,繼續加載剩餘的資料,當資料加載完成,不再繼續加載
WaterFall.prototype.mouseEnd = function(){
    var t = this;
    window.onscroll = function(){
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        var clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
        if(scrollTop + clientHeight > t.obj.offsetHeight){
            if(t.isEnd){
                return;
            }
            // 當目前頁面的總資料量大于jsonp傳遞過來的資料量時,将isEnd設定為true
            // 并将頁面總資料量設定為jsonp傳遞過來的資料量
            // 目前頁數設定為jsonp傳遞過來的資料量除以每頁資料,并向上取整
            if(t.num >= t.data.length){
                t.isEnd = true;
                t.num = t.data.length;
                t.page = Math.ceil(t.data.length / t.count);
            }else{
                // 如果目前頁面的總資料量小于或等于jsonp傳遞過來的資料量時,
                // 目前頁數加1,更新目前頁面總資料量
                t.page++;
                t.num = t.count * t.page;
                // 如果目前頁面的總資料量剛好等于jsonp傳遞過來的資料量時,也将isEnd設定為true
                if(t.num == t.data.length){
                    t.isEnd = true;
                }
            }
            // 根據頁面總資料量建立節點及更新節點位置
            t.createElements();
            t.updatePosition();
        }
    };
};