Javascript 瀑布流實現的兩種方式:固定列數的浮動布局與絕對定位自適應寬度


瀑布流已經火了一段時間了,自己最近研究了一下,網上關於瀑布流的帖子也很多,網上一般是說三種方式,固定列數的浮動布局,CSS3列布局,絕對定位布局

推薦兩個關於瀑布流的帖子,寫得比我詳細多了:

迅雷的:http://cued.xunlei.com/log031

張鑫旭的:網址太長點我

這里主要是記錄一下我的實現方式,用數組模擬的數據,也可以用AJAX實現讀取數據,底部提供DEMO代碼下載!

一、固定列數的浮動布局

  這種方式簡單適用,先按照列數把布局固定好,然后在滾動事件中分別在每一列插入相應的數據既可,代碼比較簡單:

  其實就一個滾動加載事件。我這里沒有做按高低排序。

      點擊查看DEMO演示

     代碼如下:  

View Code
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>瀑布流布局(基於固定寬度的浮動定位)</title>
    <link rel="stylesheet" href="style/style.css">
</head>
<body>
<div id="warp" class="warp">
    <div class="full" id="row1">
        <div class="water">
            <a href="javascript:void(0)"><img src="images/01.JPG" alt=""></a>
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/02.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/09.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/15.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
    </div>
    <div class="full" id="row2">
        <div class="water">
            <img src="images/03.jpg" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/04.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/10.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/08.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
    </div>
    <div class="full" id="row3">
        <div class="water">
            <img src="images/05.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/06.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/11.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/14.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
    </div>
    <div class="full last" id="row4">
        <div class="water">
            <img src="images/07.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/08.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/12.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
        <div class="water">
            <img src="images/13.JPG" alt="">
            <p class="title">瀑布流布局</p>
        </div>
    </div>
</div>
<script type="text/javascript" src="style/waterfull.js"></script>
</body>
</html>

  JS代碼:  

View Code
/* *
  * 基於固定寬度的浮動定位的瀑布流
  * 實現簡單,其實就是一個滾動加載數據而已
  * 缺點布局不隨寬度的變化而改變,如果有圖片特別長的時候,最高的列與最低的列有可能差距大,空白大
  * by VVG http://www.cnblogs.com/NNUF/
  */
var WaterFull = {
    $:function(id){return document.getElementById(id);},
    // 每次滾動需要加載的數據,可以用ajax替代讀取,每次分批加載
    data:[{imgUrl:'images/01.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位01'},
          {imgUrl:'images/02.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位02'},
          {imgUrl:'images/03.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位03'},
          {imgUrl:'images/05.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位04'},
          {imgUrl:'images/06.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位05'},
          {imgUrl:'images/07.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位06'},
          {imgUrl:'images/08.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位07'},
          {imgUrl:'images/09.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位08'},
          {imgUrl:'images/10.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位09'},
          {imgUrl:'images/11.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位10'},
          {imgUrl:'images/12.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位11'},
          {imgUrl:'images/13.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位12'},
          {imgUrl:'images/14.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位13'},
          {imgUrl:'images/15.jpg',link:'javascript:void(0)',title:'瀑布流浮動定位14'}
          ],
    createChild:function(link,imagesUrl,title){
        var str = '<a href="' + link + '"><img src="' + imagesUrl + '"></a>' + '<p class="title">' + title + '</p>';
        var div = document.createElement('div');
        div.className = 'water';
        div.innerHTML = str; 
        return div;
    },
    //綁定事件
    on:function(element, type, func) {
        if (element.addEventListener) {
            element.addEventListener(type, func, false); //false 表示冒泡
        } else if (element.attachEvent) {
            element.attachEvent('on' + type, func);
        } else {
            element['on' + type] = func;
        }
    },
    //獲取列高度,返回數組,從小到大排序
    getRowByHeight:function(){
        var row = [this.$('row1'),this.$('row2'),this.$('row3'),this.$('row4')];
        var height = [];
        for(var i = 0;row[i];i++){
            row[i].height = row[i].offsetHeight;
            height.push(row[i]);
        }
        // 對高度進行排序,低--》高,保證最矮的優先加載
        height.sort(function(a,b){
            return a.height - b.height;
        });
        return height;
    },
    //獲取頁面總高度(總高度 = 卷去高度 + 可視區域高度)
    getPageHeight:function(){
        return document.documentElement.scrollHeight || document.body.scrollHeight ;
    },
    // 獲取頁面卷去的高度
    getScrollTop:function(){
        return document.documentElement.scrollTop || document.body.scrollTop;
    },
    // 獲取頁面可視區域寬度
    getClientHeigth:function(){
        return document.documentElement.clientHeight || document.body.clientHeight;
    },
    append:function(){
        var i = 0,rows = this.getRowByHeight(),div,k;
        for(;this.data[i];i++){
            div = this.createChild(this.data[i].link, this.data[i].imgUrl,this.data[i].title);
            // 因為是4列,所以數據以4列一個輪回加載
            k = ((i+1)>4)?i%4:i;            
            // 在列上添加數據
            rows[k].appendChild(div);
        }
    },
    onScroll:function(){
        // 獲取高度等數據
        var height = WaterFull.getPageHeight();
        var scrollTop = WaterFull.getScrollTop();
        var clientHeight = WaterFull.getClientHeigth();
        // 如果滾動到最底部,就加載
        if(scrollTop + clientHeight > height - 50){
            WaterFull.append();
        }
    },
    timer:null
};
WaterFull.on(window, 'scroll',function(){
    clearTimeout( WaterFull.timer ); //清除上一次,性能優化
    WaterFull.timer = setTimeout(WaterFull.onScroll,500);
});

 

二、絕對定位實現的瀑布流,寬度自適應,resize重排

  絕對定位實現方式因為要獲取每格的高度,然后根據高度來計算定位位置,所以必須要知道圖片的高度,如果沒有高度,定位就不准確,所以傳遞數據的時候需要圖片的高度。

  點擊查看DEMO演示

  我是這樣計算絕對定位的位置的,left根據列數來,這個略過,下面主要講TOP值的獲取:

  比如如下的排列方式,數字代表格子

  0    1     2     3    4     5

      6    7    8    9     10   11

     12   13  14   15   16   17

    第12格子的絕對定位TOP值 =  第0格的高度(offsetHeight) + 相隔距離(margin) + 6格的高度(offsetHeight) + 相隔距離(margin);

  這里可以把每格的高度通過對象的屬性記錄下來,以免每次都進行offsetHeight的獲取,我的代碼里面沒有體現出來。

     這個計算就通過一個循環來實現:

  計算定位的代碼如下:     

function sort(){
            var num = getColumnNum(), left, top, column;
            //nowNum的作用是不讓已經加載的數據重新計算定位排列
            for (var j = nowNum, k = cells.length; j < k; j++, nowNum++) {
                // 初始化top的值
                top = 0;
                // 獲取當前為第幾列
                column = j < num ? j : j % num;
                // 計算可以得到當前列的LEFT值
                left = column * (cellClientWidth + columnMarginRight);
                cells[j].style.left = left + 'px';
                if (j < num) {
                    // 第一列top值為0
                    cells[j].style.top = '0px';
                } else {
                    // 計算TOP值,等於當前格子的頂上每列的高度相加
                    for (var m = column; m < j; m = m + num) {
                        top = top + cells[m].offsetHeight + columnMarginRight;
                    }
                    cells[j].style.top = top + 'px';
                }
            }
        }

 瀑布流絕對定位總代碼如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>瀑布流布局(絕對定位)</title>
    <style type="text/css">
        html, body{
            height:100%
        }

        html, body, #warp p{
            margin:0;
            padding:0
        }

        #warp{
            margin:20px auto;
            position:relative;
            min-height:1000px;
        }

        #warp .cell{
            padding:10px;
            border:1px solid #ccc;
            box-shadow:2px 2px 5px #ccc;
            overflow:hidden;
        }

        #warp .cell a{
            text-decoration:none;
            color:#878787;
            font:14px/1.5em Microsoft YaHei;
        }
        img{ border:none; }
    </style>
</head>
<body>
<div id="warp" class="warp clearfix"></div>
<script type="text/javascript">
    var data = [
        {imgUrl:'images/01.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位01', height:273},
        {imgUrl:'images/02.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位02', height:144},
        {imgUrl:'images/03.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位03', height:168},
        {imgUrl:'images/04.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位04', height:275},
        {imgUrl:'images/05.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位05', height:288},
        {imgUrl:'images/06.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位05', height:272},
        {imgUrl:'images/07.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位06', height:285},
        {imgUrl:'images/08.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位07', height:282},
        {imgUrl:'images/09.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位08', height:190},
        {imgUrl:'images/10.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位09', height:236},
        {imgUrl:'images/11.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位10', height:225},
        {imgUrl:'images/12.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位11', height:264},
        {imgUrl:'images/13.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位12', height:144},
        {imgUrl:'images/14.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位13', height:192},
        {imgUrl:'images/15.jpg', link:'javascript:void(0)', title:'瀑布流絕對定位14', height:343}
    ];
    var waterFull = function (options) {
        var id = options.id,
                picWidth = options.picWidth || 190,
                columnPadding = options.columnPadding || 10,
                columnBorder = options.columnBorder || 1,
                columnMarginRight = options.columnMargin || 20,
                // 格子總寬度
                cellClientWidth = picWidth + columnPadding * 2 + columnBorder * 2,
                obody = document.getElementsByTagName('body')[0],
                owarp = document.getElementById(id),
                // 用於記錄當前插入的格子數量
                nowNum = 0,
                cells = []; // 用於記錄每個單獨層對象

        // 獲取列數
        function getColumnNum() {
            // 根據每列的寬度來計算總共的列數
            var columnNum = Math.floor(obody.clientWidth / (cellClientWidth + columnMarginRight));
            // 然后再設置owarp的寬度,是其保持居中
            owarp.style.width = columnNum * (cellClientWidth + columnMarginRight) - columnMarginRight + 'px';
            return columnNum;
        }

        // 創建格子
        function createCell(left, top, link, imgUrl, imgHeight, title) {
            var cssText = 'position:absolute;left:' + left + 'px;top:' + top + 'px';
            var inHTML = '<a href="' + link + '" target="_blank"><img src="' + imgUrl + '" alt="' + title + '" height="' + imgHeight + 'px"><p class="title">' + title + '</p></a>';
            //console.log(inHTML);
            var div = document.createElement('div');
            div.className = 'cell';
            div.style.cssText = cssText;
            div.innerHTML = inHTML;
            return div;
        }

        // 插入數據
        function insert(data) {
            var fragElement = document.createDocumentFragment();
            if (data.length > 0) {
                for (var i = 0, n = data.length; i < n; i++) {
                    var cell = createCell(-9999, -9999, data[i].link, data[i].imgUrl, data[i].height, data[i].title);
                    fragElement.appendChild(cell);
                    cells.push(cell);
                }
                owarp.appendChild(fragElement);
            }
            // 插入后再排序
            sort();
        }

        //排序
        function sort(){
            var num = getColumnNum(), left, top, column;
            //nowNum的作用是不讓已經加載的數據重新計算定位排列
            for (var j = nowNum, k = cells.length; j < k; j++, nowNum++) {
                // 初始化top的值
                top = 0;
                // 獲取當前為第幾列
                column = j < num ? j : j % num;
                // 計算可以得到當前列的LEFT值
                left = column * (cellClientWidth + columnMarginRight);
                cells[j].style.left = left + 'px';
                if (j < num) {
                    // 第一列top值為0
                    cells[j].style.top = '0px';
                } else {
                    // 計算TOP值,等於當前格子的頂上每列的高度相加
                    for (var m = column; m < j; m = m + num) {
                        top = top + cells[m].offsetHeight + columnMarginRight;
                    }
                    cells[j].style.top = top + 'px';
                }
            }
        }

        // resize 重新排列
        function resort() {
            // 設置nowNum=0即可重排
            nowNum = 0;
            // 重排
            sort();
        }
        // 暴露接口
        return {
            insert:insert,
            resort:resort
        }

    };
    var tool = {
        on:function (element, type, func) {
            if (element.addEventListener) {
                element.addEventListener(type, func, false); //false 表示冒泡
            } else if (element.attachEvent) {
                element.attachEvent('on' + type, func);
            } else {
                element['on' + type] = func;
            }
        },
        getPageHeight:function () {
            return document.documentElement.scrollHeight || document.body.scrollHeight;
        },
        // 獲取頁面卷去的高度
        getScrollTop:function () {
            return document.documentElement.scrollTop || document.body.scrollTop;
        },
        // 獲取頁面可視區域寬度
        getClientHeigth:function () {
            return document.documentElement.clientHeight || document.body.clientHeight;
        },
        timer:null,
        timer2:null
    };
    var myWaterFull = waterFull({id:'warp'});
    // 初始化的數據
    myWaterFull.insert(data);
    tool.on(window, 'scroll', function () {
        clearTimeout(tool.timer); //清除上一次,性能優化
        tool.timer = setTimeout(function () {
            var height = tool.getPageHeight();
            var scrollTop = tool.getScrollTop();
            var clientHeight = tool.getClientHeigth();
            // 如果滾動到最底部,就加載
            if (scrollTop + clientHeight > height - 50) myWaterFull.insert(data);
        }, 500);
    });
    tool.on(window, 'resize', function () {
        clearTimeout(tool.timer2);
        tool.timer2 = setTimeout(function () {
            myWaterFull.resort();
        }, 500)
    })
</script>
</body>
</html>

 

DEMO下載:點擊下載

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM