javascript瀑布流效果

龍恩0707發表於2014-07-17

javascript瀑布流效果

    其實javascript瀑布流 前幾年都已經很流行了(特別是美麗說,蘑菇街),最近看到網上有人問這個瀑布流效果,所以自己有空的時候就研究了下,其實也是研究別人的程式碼,研究了下別人寫的思路,所以有了一個自己的版本程式碼。下面來講講瀑布流的思路吧!

    思路:1.先計算當前螢幕或者當前容器最多能容納幾列瀑布,其計算方法為 maxCol =  "Math.floor(螢幕可見區域寬度或者容器可視區寬度 / (格子寬度+間距))";

            2. 如果當前的容器沒有定寬度話,可以設定容器的寬度為:width = 列數* (格子寬度+間距) – 間距. 因為 當容器的寬度計算出來之後再顯示,否則會造成頁面寬度的抖動,影響體驗。計算方法可以理解如下:

上面列數為 6列 ,5個間距,因為最右邊間距不算的,所以容器的計算方法為:width = 列數 * (格子寬度+間距) - 間距。

         3.   排序: 目前支援2種插入方式: 1. 計算出每列最短的高度,依次插入。2. 每列是按順序插入進去。

 下面還是看看JSFiddler效果吧!

  親,請點選我看效果!

元件配置項如下:

   container
  '',    瀑布流容器 必填項
 columnWidth  '204',     列寬度 必填
 columnClassName  'columnCls',        // 列類名  必填
 columnSpace  10,                 // 列間距
 cellCls   '.cell',            // 每一列單元格class類名
isLoadTarget 'img',              // 要載入目標選擇器 預設為img
isAutoLoadHeight  true,               // 是否需要自動計算圖片的高度
fadeIn

true,               // 是否漸顯載入 預設為true


 speed  500,                // 漸顯速率 預設為500(毫秒)
 type  1,                  // 插入方式 1為插入最短那列,2 為按順序插入
 diff  100                 // 滾動時, 當最小高度的列超過在螢幕高度+已滾動高度+diff時, 會去載入更多資料

程式碼分析如下:

 1. 初始化方法:_init(); 1. 建立列,2. 渲染頁面內容。3.處理視窗滾動及縮小視窗事件。如下圖所示:

 

 

下面是所有的JS程式碼如下:

/**
 * JS瀑布流佈局
 * @ver 1.0
 * @param {options,callback} 物件配置項 回撥
 **/
 
 function WaterFall(options,callback) {
    var self = this;
    self.options = $.extend({},defaults,options || {});
    this.cache = {
        $columns   : 0,   // 所有的列
        loadIndex  : 0    // 載入的次數
    };
    self.callback = callback;
    this._init();
 }
 $.extend(WaterFall.prototype,{
    
    /*
     * 程式碼初始化 {建立列操作 對已存在的元素排序 視窗縮放或滾動事件}
     * @method _init {private}
     */
    _init: function(){
        var self = this,
            cache = self.cache;
        var cfg = self.options;
        if(cfg.container == '') {return;}
        cache.$columns = self._createColumn();

        //重排已存在元素時強制不漸顯
        self.render($(cfg.container).find(cfg.cellCls),false);
        
        var scrollTime,
            resizeTime;

        $(window).unbind('scroll').bind('scroll',function(){
            scrollTime && clearTimeout(scrollTime);
            scrollTime = setTimeout(function(){
                self._onScroll();
            },100);
        });

        $(window).unbind('resize').bind('resize',function(){
            resizeTime && clearTimeout(resizeTime);
            resizeTime = setTimeout(function(){
                self._onResize();
            },100);
        });
    },
    /*
     * 建立列
     * @method _createColumn {private}
     */
    _createColumn: function(){
        var self = this,
            cfg = self.options;
        var columnLen = self._calculateColumns();
        var html = "";
        for(var i = 0; i < columnLen; i++) {
            html+= '<div class="'+cfg.columnClassName+'" style="width:'+cfg.columnWidth+'px;display:inline-block;vertical-align:top;*display:inline;zoom:1;margin-left:'+cfg.columnSpace/2+'px;margin-right:'+cfg.columnSpace/2+'px;overflow:hidden"></div>'
        }
        $(cfg.container).prepend(html);
        return $('.'+cfg.columnClassName,cfg.container);//列集合
    },
    /*
     * 共有多少列
     * 計算方法: maxCol = Math.floor(螢幕可見區域的寬度或者父容器的寬度/(格子寬度+間距));
     * @method _calculateColumns {private}
     */
    _calculateColumns: function(){
        var self = this,
            cfg = self.options;
        var num = Math.floor($(cfg.container).outerWidth()/(cfg.columnWidth *1 + cfg.columnSpace*1));
        if(num < 1){num = 1;}
        return num;
    },
    /*
     * 渲染內容
     * @param {elements flag} 所有.cell類元素  boolean
     */
    render: function(elements,flag){
        var self = this,
            cfg = self.options,
            cache = self.cache;

        if($(elements).length <= 0) {return;}
        $(elements).each(function(index,$this){
            if(!cfg.isAutoLoadHeight) { //如果給出了圖片高度 不需要自動計算高度
                if(cfg.type == 1) {
                    self._byShortInsert($(this),cfg.fadeIn && flag);//插入最短那列
                }else if(cfg.type == 2){
                    self._byOrderInsert($(this),cfg.fadeIn && flag);// 按順序插入
                }
            }else {
                self._renderHTML($(this),flag,index);
            }
        });
    },
    _renderHTML: function(elem,flag,index){
        var self = this,
            cfg = self.options;
        if($(elem)[0].nodeName.toLowerCase()=='img'|| $(elem).find(cfg.isLoadTarget).length > 0) {
            var image = new Image();
            var src = $(elem)[0].nodeName.toLowerCase()=='img' ? $(elem).attr('src'):$(elem).find(cfg.isLoadTarget).attr('src');

            //圖片載入後才能自動計算出尺寸 除IE以外的瀏覽器
            image.onload = function(){
                image.onreadystatechange=null;
                if(cfg.type == 1) {
                    self._byShortInsert(elem,cfg.fadeIn && flag);//插入最短那列
                }else if(cfg.type == 2){
                    self._byOrderInsert(elem,cfg.fadeIn && flag,index);// 按順序插入
                }
                image = null;
            };
            // 針對IE私有 onreadystatechange
            image.onreadystatechange = function(){
                 if(image.readyState == "complete"){
                     image.onload=null;
                     if(cfg.type==1){ 
                        self._byShortInsert(elem,cfg.fadeIn && flag);//插入最短那列
                     }else if(cfg.type == 2){
                        self._byOrderInsert(elem,cfg.fadeIn && flag);// 按順序插入
                     }
                     image=null;
                 }
            }
            image.src=src;
        }else {
            if(cfg.type == 1) {
                self._byShortInsert(elem,cfg.fadeIn && flag);//插入最短那列
            }else if(cfg.type == 2){
                self._byOrderInsert(elem,cfg.fadeIn && flag,index);// 按順序插入
            }
        }
    },
    /*
     * 按最短的那列插入
     * @method _byShortInsert
     * @param {elem flag}
     */
    _byShortInsert: function(elem,flag){
        var self = this,
            cfg = self.options,
            cache = self.cache;

        var $columns = cache.$columns;
        if(flag) { //漸顯
            var calculateLowest = self._calculateLowest();
            $(elem).css('opacity',0).appendTo($columns.eq(calculateLowest)).fadeTo(cfg.speed,1);
        }else {
            //不漸顯
            var calculateLowest = self._calculateLowest();
            $(elem).appendTo($columns.eq(calculateLowest));
        }
    },
    /*
     * 計算最短的那列的索引
     * @method _calculateLowest {private}
     * @return 返回列最短的索引 index
     */
    _calculateLowest: function(){
        var self = this,
            cache = self.cache;
        var $columns = cache.$columns,
            index = 0;
        // 獲取第一列的高度 迴圈 依次對比 然後返回最小的高度
        var firstHeight = $columns.eq(0).outerHeight();
        for(var i = 0; i < $columns.length; i++){
            var curHeight = $($columns[i]).outerHeight();
            if(curHeight < firstHeight) {
                firstHeight = curHeight;
                index = i;
            }
        }
        return index;
    },
    /*
     * 按順序插入
     * @method _byOrderInsert {private}
     */
    _byOrderInsert: function(elem,flag,index){
        var self = this,
            cfg = self.options;
        var columnLen = self._calculateColumns(),
            $columns = cache.$columns;
        if(flag) { //漸顯
            $(elem).css('opacity',0).appendTo($columns.eq(index % columnLen)).fadeTo(cfg.speed,1);
        }else { //不漸顯
            $(elem).appendTo($columns.eq(index % columnLen));
        }
    },
    /*
     * 滾動到底部時 再進行載入
     */
    _onScroll: function(){
        var self = this,
            cfg = self.options,
            cache = self.cache;
        var lowestIndex = self._calculateLowest(),
            $lowest_column = cache.$columns.eq(lowestIndex);

        //最短列底部距離瀏覽器視窗頂部的距離
        var colHeight = $lowest_column.offset().top + $lowest_column.outerHeight();

        // 當最小高度的列超過在螢幕高度+已滾動高度+diff時, 會去載入更多資料
        if(cfg.diff + $(window).scrollTop() + $(window).outerHeight() >= colHeight) {
            cache.loadIndex++;
            if(self.callback && $.isFunction(self.callback)){
                self.callback(cache.loadIndex);
                var curHtml = self.callback(cache.loadIndex);
                self.render(curHtml,true);
            } 
        }
    },
    /*
     * 視窗縮放時候 重新排序
     */
    _onResize: function(){
        var self = this,
            cfg = self.options,
            cache = self.cache;
        var num = self._calculateColumns();

        // 如果列數沒有變 返回
        if(num == cache.$columns.length) {
            return;
        }
        var $cells=$(cfg.container).find(cfg.cellCls);
        cache.$columns.remove();
        cache.$columns = self._createColumn();
        self.render($cells,false);
    }
 });
 var defaults = {
    container            :      '',                 // 需要載入的容器 (必填)
    columnWidth          :      '204',              // 列寬
    columnClassName      :      'columnCls',        // 列類名
    columnSpace          :      10,                 // 列間距
    cellCls              :      '.cell',            // 每一列單元格class類名
    isLoadTarget         :      'img',              // 要載入目標選擇器 預設為img
    isAutoLoadHeight     :      true,               // 是否需要自動計算圖片的高度
    fadeIn               :      true,               // 是否漸顯載入 預設為true
    speed                :      500,                // 漸顯速率 預設為500(毫秒)
    type                 :      1,                  // 插入方式 1為插入最短那列,2 為按順序插入
    diff                 :      100                 // 滾動時, 當最小高度的列超過在螢幕高度+已滾動高度+diff時, 會去載入更多資料.
 };

demo下載:

相關文章