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下载:点击下载

  

你可能感兴趣的:(JavaScript)