多种方式实现web瀑布流布局

据说是蘑菇街的web端面试题:"用至少两种方式实现瀑布流布局?"
其实百度一查有很多种方式.我整理三种:CSS,JS,jQuery,望温故而知新.
不一定是最好的,但是注释很详细,有点基础的肯定能看懂.

效果是这样的,上滑加载更多图片(假数据):
ps:能认出来这些图来源的握个爪,擦擦眼泪,不解释...

1:JavaScript

.html文件(三种方式都相同,就是内容,没啥说的):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>瀑布流首页</title>
    <link href="css/index.css" rel="stylesheet">
</head>
<body>
    <!--父盒子-->
    <div id="main">
        <!--单个盒子-->
        <div class="box">
             <!--图片盒子-->
            <div class="pic">
                <img src="images/1.jpg"/>
            </div>
        </div>
    <!--单个盒子标签复制20次...图片名字改改...-->
    </div>
<!--jQuery方式需要引入jQuery库,JS方式与CSS方式都要注释掉-->
<script src="js/jquery-3.1.1.min.js" type="text/javascript"></script>
<!--引入JS,CSS方式注释掉-->
<script src="js/index.js" type="text/javascript"></script>
</body>
</html>

.css文件(JS方式与jQuery方式相同,CSS方式肯定要改):

*{
    /*去除边距*/
    margin:0;
    padding: 0;
    /*html性能优化:虚拟dom,如果一个html标签没有设置css样式,就是虚拟的,
     所以无论设置多少层div都对性能没有影响*/
}
#main{
    /*定位*/
    position: relative;
}
.box{
    /*内边距*/
    padding:15px 0 0 15px ;
    float: left;
}
.pic{
    /*边框*/
    border:1px solid #dddddd;
}
.pic img{
    width: 165px;
}

.js文件:

/**
 * Created by Mac on 2017/1/7.
 */
function $(id) {
    //判断id的类型
    return typeof id === 'string'?document.getElementById(id):id;
}

//当网页加载完毕
window.onload = function () {
    //瀑布流布局 保证传的参数能够找到父盒子
    waterFall('main','box');
    
    //滚动加载盒子
    window.onscroll = function ()
    {
        //判断是否加载
        if (checkWillLoad())
        {
            //创造假数据
            var data = {'dataImg':[{'img':'23.jpg'},{'img':'24.jpg'},{'img':'25.jpg'},{'img':'26.jpg'},{'img':'27.jpg'},{'img':'28.jpg'}]};
            //加载数据
            for(var i=0; i<data.dataImg.length; i++)
            {
                //创建最外面的盒子
                var newBox = document.createElement('div');
                newBox.className = 'box';
                $('main').appendChild(newBox);
                //创建单个盒子
                var newPic = document.createElement('div');
                newPic.className = 'pic';
                newBox.appendChild(newPic);
                //创建img
                var newImg = document.createElement('img');
                newImg.src = 'images/' + data.dataImg[i].img;
                newPic.appendChild(newImg);
            }
            //把刚创建的盒子瀑布流布局
            waterFall('main','box');
        }
    }
}

//实现瀑布流布局
//规则:从第二行开始的图片,总是拼接在上一行高度最矮的图片后面
function  waterFall(parent,box) {
    //父盒子居中
    //通过父盒子拿到所有的子盒子
    var allBox = $(parent).getElementsByClassName(box);
    //求出盒子的宽度
    var boxWidth = allBox[0].offsetWidth;
    //求出浏览器的宽度(包括边框的宽高)
    var screenWidtn = document.body.offsetWidth;
    //求出列数 //取整函数取整
    var cols = Math.floor( screenWidtn/boxWidth);
    //父标签居中
    //先求出父标签宽度
    $(parent).style.width = boxWidth * cols + 'px';
    //居中
    $(parent).style.margin = '0 auto';
    
    //子盒子定位
    //创建一个高度数组,存所有的高度
    var heightArr = [];
    //遍历
    for(var i = 0; i < allBox.length ;i++)
    {
        //求出每个盒子的高度
        var boxHeight = allBox[i].offsetHeight;
        //第一行的盒子不需要重新定位//每一行的盒子数与列数相同
        if(i<cols)
        {
            //添加第一行所有盒子高度
            heightArr.push(boxHeight);
        }
        else//剩下的盒子都需要瀑布流布局
        {
            //求出最矮的盒子高度
            var minBoxHeight = Math.min.apply(this,heightArr);
            //求出最矮盒子对应的索引
            var minBoxIndex = getMinBoxIndex(minBoxHeight,heightArr);
            //盒子瀑布流定位  顶部间距就是最矮盒子的高度
            allBox[i].style.position = 'absolute';
            allBox[i].style.top = minBoxHeight + 'px';
            allBox[i].style.left = minBoxIndex * boxWidth +'px';
            //关键:更新数组最矮高度,使下一个图片在高度数组中总是找最矮高度的图片下面拼接
            heightArr[minBoxIndex] += boxHeight;
        }
    }
}

//求出最矮盒子对应的索引函数
function getMinBoxIndex(val,arr) {
    for(var i in arr)
    {
        if(val == arr[i])
        {
            return i;
        }
    }
}

//加载更多规则:当浏览器最下方到达图片的高度一半时让其刷新出来
//判断是否符合加载条件
function checkWillLoad() {
    //取出所有盒子
    var allBox = $('main').getElementsByClassName('box');
    //取出最后一个盒子
    var lastBox = allBox[allBox.length - 1];
    //求出最后一个盒子高度的一半 + 内容与浏览器头部的偏离位置
    var lastBoxDis = lastBox.offsetHeight * 0.5 + lastBox.offsetTop;
    //求出浏览器的高度
    // 注意:JS代码存在浏览器兼容问题 一般分标准模式(按屏幕算document.body.offsetHeight)和混杂模式(按所有内容算)
    var screenHeight =  document.documentElement.clientHeight;
    //页面偏离屏幕的高度
    var scrollTopHeight = document.body.scrollTop;
    //判断
    return lastBoxDis <= screenHeight + scrollTopHeight;
}

2:jQuery方式的.js文件:
jQuery的API中文文档:http://jquery.cuishifeng.cn/index.html

简单介绍一下jQuery:
JS存在的问题:    
1:浏览器兼容问题    
2:JS存在复杂的dom操作,实现特效动画复杂    
3:请求网络数据存在跨域问题,跨域问题就是自动做代码保护,不允许跨域调用其他页面的对象,
  类似中国的墙'长城',即只能访问当前服务器的网址,无法访问外界的网址,解决方法百度上很多,
  但一般是后台处理,我并没有做过,所以就不细写了
jQuery优势:   
1.几乎不存在浏览器兼容问题    
2.轻松实现dom操作,特效,动画   
3.多种方式的网络请求方案
// document.write("<script src='jquery-3.1.1.min.js'></script>");
//当页面加载完毕
$(window).on('load',function () {
    //1.实现瀑布流布局
    waterFall();
    
    //2.滚动加载
    $(window).on('scroll',function () {
        //判断是否加载
        if (checkWillLoad())
        {
            ////创造假数据
            var data = {'dataImg':[{'img':'23.jpg'},{'img':'24.jpg'},{'img':'25.jpg'},{'img':'26.jpg'},{'img':'27.jpg'},{'img':'28.jpg'}]};
            //遍历创建盒子
            $.each(data.dataImg,function (index,value)
                   {
                       //创建一个div标签 设置它的类为'box' 添加到'main'里面去
                       var newBox = $('<div>').addClass('box').appendTo($('#main'));
                       var newPic = $('<div>').addClass('pic').appendTo($(newBox));
                       //创建img  取出遍历的对象value的img属性对应的值
                       $('<img>').attr('src','images/'+$(value).attr('img')).appendTo($(newPic));
                   })
            //1.实现瀑布流布局
            waterFall();
        }
    });
});

//实现瀑布流布局
function waterFall () {
    //拿到所有的盒子
    var allBox = $('#main > .box');
    //取出其中一个盒子的宽度
    var boxWidth = $(allBox).eq(0).outerWidth();
    //取出屏幕的高度
    var screenWidth = $(window).width();
    //求出列数 //取整函数取整
    var cols = Math.floor( screenWidth/boxWidth);
    //父标签居中
    $('#main').css({
        'width':cols * boxWidth + 'px',
        'margin':'0 auto'
    });
    //对子盒子定位
    var heightArr = [];
    //遍历
    $.each(allBox,function (index,value) {
        //取出单独盒子的高度
        var boxHeight = $(value).outerHeight();
        //判断是否第一行
        if(index < cols)
        {
            heightArr[index] = boxHeight;
        }
        else  //剩余的盒子要瀑布流布局
        {
            //求出最矮的盒子高度
            var minBoxHeight = Math.min.apply(null,heightArr);
            //取出最矮高度对应的索引  封装了js的这个方法
            var minBoxIndex = $.inArray(minBoxHeight,heightArr);
            //定位
            $(value).css({
                'position':'absolute',
                'top':minBoxHeight + 'px',
                'left':minBoxIndex * boxWidth + 'px'
            });
            //更新数组中最矮的高度
            heightArr[minBoxIndex] += boxHeight;
        }
    })
    
}

//判断是否符合加载条件
function checkWillLoad() {
    //直接取出最后一个盒子
    var lastBox = $('#main > div').last();
    //取出最后一个盒子高度的一半 + 头部偏离的位置
    var lastBoxDis = $(lastBox).outerHeight() + $(lastBox).offset().top;
    //求出浏览器的高度
    var clientHeight = $(window).height();
    //求出页面偏离浏览器高度
    var scrollTopHeight = $(window).scrollTop();
    //比较返回
    return lastBoxDis <= clientHeight + scrollTopHeight;
    
}

3:CSS方式修改一下.css中的内容即可:
主要是利用了css3中增加了一个新的属性:column
具体看看这个很详细了:http://www.tuicool.com/articles/RvY3Yv

#main{
    /*定位*/
    /*position: relative;*/
    /*多栏布局 设置栏宽度*/
    -webkit-column-width:202px;
    -moz-column-width:202px;
    column-width:202px;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

  • 今天30岁了,结婚晚。一直备孕不孕,就医先查出来排卵不好,长的过慢。上周去查了输卵管,又有一侧通而不畅,又是考虑盆...
    花花世界一股清流阅读 515评论 0 0
  • 昨天一篇《黄老师,黄小厨的钱我们不要了》在朋友圈火热刷屏。刷屏的背后,行业内一些阴暗面浮出水面。这绝对不是第一起骗...
    小爱说电影阅读 326评论 0 0
  • 最喜欢的就是这时节,月缺未圆,暖风拂面,和狗一起漫步水边月光下。 白天的暑热渐渐散去,空气中还留着一丝温热。浅淡月...
    猫果树阅读 1,161评论 0 0
  • 她叫余旭,川妹子。她是仙女,因为她会飞。她是英雄,因为她是军人。 在刷微博的时候突然看见这个消息,触动很大。不知道...
    嘿_老妖阅读 213评论 0 1