美文网首页前端攻城狮大前端常用效果
多种方式实现web瀑布流布局

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

作者: oldSix_Zhu | 来源:发表于2017-01-08 17:21 被阅读11245次

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

    相关文章

      网友评论

      • 6a0e953f7799:亲,这个父元素高度怎么自适应啊 我这个没办法自适应
      • cherish_rish:你好 还记得你发的这个瀑布流么? 我比着写了一遍 有点问题想问问你
        cherish_rish:@oldSix_Zhu 就是在页面进行渲染的时候必须要加入延时才可以么 如果不加会出现加载没有完全就执行判断的位置的情况?
        oldSix_Zhu:@cherish_rish 啥问题?直接说呗

      本文标题:多种方式实现web瀑布流布局

      本文链接:https://www.haomeiwen.com/subject/vqnqbttx.html