1. 程式人生 > >瀑布流實現

瀑布流實現

 

 <div id="all">
        <div class="box"><div class="pic"><img src="images/img01.jpg" alt=""></div></div>
        <div class="box"><div class="pic"><img src="images/img02.jpg" alt=""></div></div>
        <div class="box"><div class="pic"><img src="images/img03.jpg" alt=""></div></div>
        <div class="box"><div class="pic"><img src="images/img04.jpg" alt=""></div></div>
        <div class="box"><div class="pic"><img src="images/img05.jpg" alt=""></div></div>
</div>

 佈局:最外層由一個大的盒子包裹,裡面的圖片被兩層div包裹,具體的佈局效果可以參照上面的圖片,其中class為box盒子指的是圖中的紅色區域,這樣處理的好處是便於確認left值,由於每個小盒子都是定位出來的,用盒子的寬度值乘以當前盒子位於的列數,便可計算出left值。

css:設定box元素的上左的padding值,再設定pic元素的padding值便可實現上圖的效果,總體來說瀑布流效果的佈局和樣式還是比較容易的,只需要確定box元素的區域即可。

*{margin: 0;padding: 0;border: none;}
img{vertical-align: top;}

#all{position: relative;}
.box{
    float: left;
    padding: 15px 0 0 15px;
}
.pic{
    padding: 10px;
    border: 1px solid #ccc;
    background-color: #fff;
    border-radius: 5px;
}
.pic img{
    width: 165px;   
}

接下來就是邏輯的處理,步驟如下。

首先,我們需要將最外層的盒子居中顯示,也就是class為all的區域,若想讓塊級元素居中顯示,我們就要確定all的寬度,用螢幕的寬度除以每個子盒子的寬度可以求出圖片的列數,再用列數乘以每個盒子的寬度即可求出all的width屬性值。

其次,我們需要定位除了第一行以外的子盒子,定位的核心思想是將第二行的第一個圖片銜接到第一行高度最小盒子的底部,此時我們需要獲取第一行每個盒子的高度,將這些數值置於陣列中,借用underscore類庫的._min方法找到陣列中的最小值,遍歷陣列,找到與最小值相等的陣列的索引,確認最小高度值後便可定位銜接圖片的top和left值,top值比較容易確認,就是最小高度值,left值可以通過當前盒子的索引乘以每個盒子的寬度來確定。以上步驟實現完畢後,不要忘記更新陣列(否則所有的盒子都會重疊到一起)更新的方法不是很複雜,只需要用最小值加上當前盒子的高度。

function waterFull(parent,child){
    //1.讓父盒子居中顯示
        //1.1獲取所有的子盒子
    var allBox=$(parent).getElementsByClassName(child);
        //1.2獲取子盒子寬度
    var boxWidth=allBox[0].offsetWidth;
        //1.3獲取螢幕的寬度
    var screenX=document.documentElement.clientWidth;
        //1.4獲取列數
    var cols=parseInt(screenX/boxWidth);
        //1.5父盒子寬度確定並居中顯示
    $(parent).style.width=cols*boxWidth+'px';
    $(parent).style.margin='0 auto';

 //2.子盒子定位
        //2.1定義各種變數
        var heightArr=[],boxHeight=0,minBoxHeight=0,minBoxIndex=0;
        //2.2遍歷所有圖片
        for(var i=0;i<allBox.length;i++){
            //2.2.1獲取每個圖片的高度
            boxHeight=allBox[i].offsetHeight;
            if(i<cols){//處理第一行圖片
                heightArr.push(boxHeight);
            }else{//其餘圖片的處理
                //2.2.2確定最小圖片的高度
                minBoxHeight=_.min(heightArr);
                //2.2.3確定最小盒子的索引
                minBoxIndex=getMinBoxIndex(heightArr,minBoxHeight);
                //2.2.4定位子盒子
                allBox[i].style.position='absolute';
                allBox[i].style.top=minBoxHeight+'px';
                allBox[i].style.left=minBoxIndex*boxWidth+'px';
                //2.2.5重新定義高度
                heightArr[minBoxIndex]+=boxHeight;
            }
        }
}
//獲取最小盒子的索引
function getMinBoxIndex(arr,val){
    for(var i=0;i<arr.length;i++){
        if(arr[i]===val){
            return i;
        }
    }
}

盒子佈局完畢後,即可開始實現瀑布流效果,當滾動條滾動到最後一個盒子一半位置時,開始載入後面的圖片(規則可以自己制定,不需要統一)如果最後盒子距離頂部的值小於等於螢幕高度與滾動高度的總和時,可以執行載入函式。這裡不要忘記加上滾動的高度。

function loadImg(){
    //1.獲取最後盒子
    var allBox=$('all').getElementsByClassName('box');
    var lastBox=allBox[allBox.length-1];
    //2.計算出最後盒子的高度
    var lastBoxH=lastBox.offsetTop+lastBox.offsetHeight*0.5;
    //2.1計算螢幕高度
    var screenH=document.documentElement.clientHeight;
    //2.2計算滾動高度
    var scrollH=scroll().top;
    //2.3返回對比結果
    return lastBoxH<=screenH+scrollH;
}

載入的資料可以動態傳入,在這裡我就自己定義了一些資料,方便操作。節點的建立和新增比較容易,這裡就不再敘述了,節點建立完畢後需要重新進行瀑布流佈局,這一步至關重要。加入定時器只是為了實現緩動載入的效果,可以自主選擇加或不加。

window.onload=function(){
    //1.瀑布流佈局
    waterFull('all','box');
    //2.動態載入圖片
    var time1=null;
    window.onscroll=function(){
        clearTimeout(time1);
        time1=setInterval(function(){
            if(loadImg()){
            //2.1建立資料
            var imgData=[
                {'src':'images/img01.jpg'},
                {'src':'images/img10.jpg'},
                {'src':'images/img17.jpg'},
                {'src':'images/img16.jpg'},
                {'src':'images/img30.jpg'},
                {'src':'images/img21.jpg'}
            ];
            //2.2不斷載入資料
            for(var i=0;i<imgData.length;i++){
                var newBox=document.createElement('div');
                newBox.className='box';
                $('all').appendChild(newBox);

                var newImg=document.createElement('div');
                newImg.className='pic';
                newBox.appendChild(newImg);

                var newData=document.createElement('img');
                newData.src=imgData[i].src;
                newImg.appendChild(newData);
            }
            //2.3重新佈局
            waterFull('all','box');
        }
       },200);
     };
            //2.4視窗大小變化
            var time2=null;
            window.onresize=function(){
                clearTimeout(time2);
                time2=setTimeout(function(){
                    waterFull('all','box');
                },200);
            }
}

利用JQuery實現瀑布流,將上面的JS程式碼改寫成JQ的即可

注意點:$.inArray() 函式用於在陣列中查詢指定值

$(function(){
    //1.瀑布流佈局
    waterFull();
    //2.動態載入圖片
    var time1=null;
    $(window).on('scroll',function(){
        clearTimeout(time1);
        time1=setInterval(function(){
            if(loadImg()){
            //2.1建立資料
            var imgData=[
                {'src':'images/1.jpg'},
                {'src':'images/10.jpg'},
                {'src':'images/17.jpg'},
                {'src':'images/16.jpg'},
                {'src':'images/30.jpg'},
                {'src':'images/21.jpg'}
            ];
            //2.2不斷載入資料
            $.each(imgData,function(index,value){
              var newBox=$('<div></div>').addClass('box').appendTo('#all');
              var newPic=$('<div></div>').addClass('pic').appendTo(newBox);
              $('<img/>').attr('src',$(value).attr('src')).appendTo(newPic);
            })
            //2.3重新佈局
            waterFull();
        }
       },200);
     });
   });
/**
 * 實現瀑布流的佈局
*/
function waterFull(){
    //1.讓父盒子居中顯示
        //1.1獲取所有的子盒子
    var allBox=$('#all>.box');
        //1.2獲取子盒子寬度
    var boxWidth=allBox.eq(0).outerWidth();
        //1.3獲取螢幕的寬度
    var screenX=$(window).width();
        //1.4獲取列數
    var cols=parseInt(screenX/boxWidth);
        //1.5父盒子寬度確定並居中顯示
    $('#all').css({
      width:cols*boxWidth+'px',
      margin:'0 auto'
    })
    //2.子盒子定位
        //2.1定義各種變數
        var heightArr=[],boxHeight=0,minBoxHeight=0,minBoxIndex=0;
        //2.2遍歷所有圖片
        $.each(allBox,function(index,value){
          boxHeight=$(value).outerHeight();
          if(index<cols){//處理第一行圖片
              heightArr.push(boxHeight);
          }else{//其餘圖片的處理
              //2.2.2確定最小圖片的高度
              minBoxHeight=Math.min.apply(this,heightArr);
              //2.2.3確定最小盒子的索引
              minBoxIndex=$.inArray(minBoxHeight,heightArr);
              //2.2.4定位子盒子
                //2.2.1獲取每個圖片的高度
              $(value).css({
                position:'absolute',
                left:minBoxIndex*boxWidth+'px',
                top:minBoxHeight+'px'
              })
              //2.2.5重新定義高度
              heightArr[minBoxIndex]+=boxHeight;
          }
        });
        }
function loadImg(){
    //1.獲取最後盒子
    var lastBox=$('#all>.box').last();
    //2.計算出最後盒子的高度
    var lastBoxH=lastBox.outerHeight()+lastBox.offset().top*0.5;
    //2.1計算螢幕高度
    var screenH=$(window).height();
    //2.2計算滾動高度
    var scrollH=$(window).scrollTop();
    //2.3返回對比結果
    return lastBoxH<=screenH+scrollH;
}