前端攻城狮大前端常用效果

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

2017-01-08  本文已影响11245人  oldSix_Zhu

据说是蘑菇街的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;
}
上一篇 下一篇

猜你喜欢

热点阅读