瀑布流,木桶,等高,圣杯,双飞翼布局

1.瀑布流布局

  • 思路:
    要求:当图片宽度相同,高度不同时;如何做一面图片墙;每次图片加载到每列最低的位置;
    1.图片的容器要相对定位,图片要相对容器绝对定位;
    2.首先要求出当浏览器打开时或者改变大小时,浏览器的窗口能放入几张图片;即形成几列;
    3.创建一个空数组来存放每列的高度值;
    4.当有图片加载时根据数组里存放的高度大小;把图片放入高度最小的列;
    5.当放入后更改放入后的高度;这样每次都可以把图片放入高度最低的列里形成好看的图片墙了。

  • 重点:

 .content{
            position:relative;
        }
 .item{
            position: absolute;
           transition:all 1s; /*渐变效果*/
         }
 function waterFull(){
                var nodeWidth =$('.item').width();//元素宽度
                var num  =parseInt($('.content').width()/nodeWidth)//一排放多少个(取整)
                var itemArr = [];//存放每列的高度;
                for(var i=0; i<num;i++){//初始化
                itemArr[i]=0;//目前每列高度为0;
            }
            
            $('.item').each(function(){//循环所有图片
                var minValue = Math.min.apply(null,itemArr) //获取数组最小值(第一次就是数组的第一项0;)
                var minIndex = itemArr.indexOf(minValue)//获取最小值的下标;

                $(this).css({//通过改变top left ;放入图片的位置;
                    top:itemArr[minIndex],
                    left:$(this).outerWidth(true)*minIndex

                })
                itemArr[minIndex] += $(this).outerHeight(true);//更改添加后列的高度
            })

     }  
  • 看下效果:
20170404_183059.gif
  • 优化:

1.在改变窗口大小时重新加载图片位置
2.当滚动时继续的加载图片;(写一个判断是否加载的函数checkScroll)
3.当滚动时发送ajax性后端要数据加载图片;(我这里是自己给的数据json模拟)
4.优化代码放入立即执行函数;

var WaterFull=(function(){
      function init(){
             waterFull()
            $(window).resize(function(){//改变窗口大小
              waterFull()
           })
            $(window).on('scroll',Scroll)//当窗口滚动时Mocks数据;
           

         }
    function waterFull(){
                var nodeWidth =$('.item').width();//元素宽度
                var num  =parseInt($('.content').width()/nodeWidth)//一排放多少个(取整)
                var itemArr = [];//存放每列的高度;
                for(var i=0; i<num;i++){//初始化
                itemArr[i]=0;//目前每列高度为0;
            }
            
            $('.item').each(function(){//循环所有图片
                var minValue = Math.min.apply(null,itemArr) //获取数组最小值(第一次就是数组的第一项0;)
                var minIndex = itemArr.indexOf(minValue)//获取最小值的下标;

                $(this).css({//通过改变top left ;放入图片的位置;
                    top:itemArr[minIndex],
                    left:$(this).outerWidth(true)*minIndex

                })
                itemArr[minIndex] += $(this).outerHeight(true);//更改添加后列的高度
            })

     }  
     function Scroll(){
          var dataInt = {
            'data':[{'src':'1.png'},{'src':'2.png'},{'src':'3.png'},{'src':'4.png'},{'src':'5.png'},{'src':'6.png'},{'src':'7.png'},
            {'src':'8.png'},{'src':'9.png'},{'src':'10.png'},{'src':'11.png'},{'src':'12.png'},{'src':'13.png'},{'src':'14.png'}]
            }
          var isArrive= false;//防止多次滚动重复数据
              if(checkScroll() && !isArrive){
                  var oParent = document.getElementsByClassName('content')[0];
                  for(var i =0;i<dataInt.data.length;i++){
                      isArrive=true;
                      var oDiv =document.createElement('div');//添加元素节点
                      oDiv.className ='item';
                      oDiv.innerHTML ='![](./img/'+dataInt.data[i].src+')'
                      oParent.appendChild(oDiv);                    
                  }
                  isArrive = false;
                  waterFull()
              }
          } 

     function checkScroll(){
             var   oParent = document.getElementsByClassName('content')[0];
             var   aDiv =oParent.getElementsByClassName('item');
             var   lastPinH=aDiv[aDiv.length-1].offsetTop+Math.floor(aDiv[aDiv.length-1].offsetHeight/2); 
             //创建【触发添加块框函数waterfall()】的高度:最后一个块框的距离网页顶部+自身高的一半(实现未滚到底就开始加载)
             var   scrollTop=$(window).scrollTop();//滚动高度
             var   winndowHeight=$(window).height(); //页面高度
             return   (lastPinH<scrollTop+winndowHeight)? true : false ; //到达指定高度后 返回true,触发waterfall()函数
        }
     return {
              init:init
          }
     })()
     
     WaterFull.init();

  • 原生js代码
  function waterFull(){
             var Oparent = document.getElementById('main');
             var aPin =Oparent.getElementsByClassName('pin')//获取存储块pin的数组;
             var num =Math.floor(document.documentElement.clientWidth/aPin[0].offsetWidth)//获取窗口每行能容纳的个数
            
             var pinHArr=[];//用于存储 每列中的所有块框相加的高度
             for(var i =0 ; i<num;i++){
                 pinHArr[i]=0;
             }
             for(var i =0 ; i<aPin.length;i++){
                
                     //获取PinHArr的最小值;
                     var minValue =Math.min.apply(null,pinHArr);
                     //获取pinHArr最小值得索引;
                     var minIndex = pinHArr.indexOf(minValue);
                       
                         aPin[i].style.top=minValue+'px';//用定位改变其top值
                         aPin[i].style.left=aPin[minIndex].offsetWidth*minIndex+'px';//用定位改变其left值
                        
                     
                     pinHArr[minIndex] += aPin[i].offsetHeight;//更改添加后列的高度
                 }
             }
  • css瀑布流效果:
20170404_221332.gif
  • 关于css瀑布流:
    方法有许多种,优缺点都有,但是本人建议用js或者jquery;因为毕竟是要向后端mock数据所以css布局不建议使用;就给出css3方法其中一种代码
     <style>
        *{padding:0;margin:0;}
        .clearfix:after,
        .clearfix:before {
        content: " ";
        display: table;
        }
        .clearfix:after {
        clear: both;
        }
        .main {
        position: relative;
        -webkit-column-width: 222px;
        -moz-column-width: 222px;
        /*column-width 属性规定列的宽度。*/
        -webkit-column-gap: 5px;
        /*column-gap 属性规定列之间的间隔。*/
        -moz-column-gap: 5px;
        }
        .box {
        float: left;
        padding: 15px 0 0 15px;
        transition: all 1s;
        }
        .box .pic {
            width: 200px;
            height: auto;
            padding: 10px;
            border-radius: 5px;
            box-shadow: 0 0 5px #cccccc;     
        }            
       .box .pic img {
               display: block;
               width: 100%;
        }
  • css3瀑布流布局:
    我们将要用到的是CSS3新加的column属性,通过指定容器的列个数column-count,列间距column-gap,列中间的边框(间隔边线)column-rule,列宽度column-width实现。

    优点:
    1. 直接用CSS定义,方便快捷,是最好不过了;
    2. 扩展方便。

    缺点:
    1. 目前仍有部分浏览器不支持CSS3;
    2.CSS3这种方式的数据排列是从上到下排列到一定高度后,再把剩余元素依次添加到下一列;

2.木桶布局

  • 思路:

1.当图片加载进来时,初始化new的image对象,给图片定一个高度;获取等比例下的宽度;
2.把图片的宽高放入一个空数组,通过循环数组获取图片的总宽度;
3.拿获取的总宽度跟容器宽度相比较,如果总宽度大于容器宽度,那就拿出最后一个图片的宽度,直到总宽度小于容器的宽度。然后拉伸容器里的图片让,图片填充这个容器的宽度(获取容器里现在的最后高度)
4.再把数组清空,放入刚才被拿出的最后放不下那一项(重置数组总宽度)
5.写一个函数渲染每排图片(把新高度传入进去)。

  • 难点
1.当图片加载进来时,初始化new的image对象,给图片定一个高度;获取等比例下的宽度;
loadImg:function(){//构建url就是一个接口;也可以是ajax;
                  var _this = this //保存作用于的this
                  var imgUrls = this.getImgUrls(40);//如果是ajax是不可能根据图片地址获取他的宽高的

                 $.each(imgUrls,function(idx,url){//所以循环这个数组,
                      var  img = new Image();//创建一个图片对象;
                      img.src =url;
                      img.onload =function(){                  
                          var imgInfo ={
                              target:$(img),//哪一张图片
                              width:200*(img.width/img.height),//  x/200=img.width/img.height
                              height:200//高度设为200;

                          }
                          _this.render(imgInfo);
                      }
                  })

               },




2.把图片的宽高放入一个空数组,通过循环数组获取图片的总宽度;
  render: function(imgInfo){
     
     
      var clientWidth = this.$ct.width();
      var rowWidth = 0;
      var newRowHeight = 0;
      var lastImgInfo = imgInfo;

      this.rowList.push(imgInfo);
      for(var i=0; i< this.rowList.length; i++){
         rowWidth = rowWidth + this.rowList[i].width;
      }


3.那获取的总宽度跟容器宽度相比较,如果总宽度大于容器宽度,那就拿出最后一个图片的宽度,直到总宽度小于容器的宽度。然后拉伸容器里的图片让,图片填充这个容器的宽度(获取容器里现在的最后高度)

 if(rowWidth > clientWidth){
        this.rowList.pop();
        rowWidth = rowWidth-lastImgInfo.width//目前每行的宽度;
        newRowHeight = clientWidth*200/rowWidth;
        //   rowWidth/200   ==  clientWidth/ X

      
      

4.再把数组清空,放入刚才被拿出的最后放不下那一项(重置数组总宽度)
         this.rowList = [];
        this.rowList.push(imgInfo);
        this.layout(newRowHeight);

5.写一个函数渲染每排图片(把新高度传入进去)
 layout: function(newRowHeight){
      console.log('createRow');
      var $rowCt = $('<div class="img-row"></div>');
      $.each(this.rowList, function(idx, imgInfo){
        var $imgCt = $('<div class="img-box"></div>'),
            $img = $(imgInfo.target);
            $img.height(newRowHeight);
            $imgCt.append($img);
            $rowCt.append($imgCt);
      });
      this.$ct.append($rowCt);

  • 效果:
20170404_222754.gif

3.等高布局

  • 思路:等高布局有几种不同的方法如定位,但目前为止我认为浏览器兼容最好最简便的应该是padding补偿法。首先把列的padding-bottom设为一个足够大的值,再把列的margin-bottom设一个与前面的padding-bottom的正值相抵消的负值,父容器设置超出隐藏,这样子父容器的高度就还是它里面的列没有设定padding-bottom时的高度,当它里面的任一列高度增加了,则父容器的高度被撑到它里面最高那列的高度,其他比这列矮的列则会用它们的padding-bottom来补偿这部分高度差。因为背景是可以用在padding占用的空间里的,而且边框也是跟随padding变化的,所以就成功的完成了一个障眼法。

  • 重点:

.wrap{         
            overflow: hidden;//父容器设置超出隐藏,这样子父容器的高度就还是它里面的列没有设定padding-bottom时的高度
        }
   .left{
            float: left;
            padding-bottom: 10000px;
            margin-bottom: -10000px;
        }
        .right{
            float: right;
            padding-bottom: 10000px;
            margin-bottom: -10000px;                          
        }
  • 看下效果:
20170404_165914.gif
  • 代码
<style>
        .wrap{
            width:100%;
            background:#ccc;
            overflow: hidden;
            min-width: 600px;
           
        }
        .left{
            width:300px;
            float: left;
            padding-bottom: 10000px;
            margin-bottom: -10000px;
            background: red;
            text-align: center;
            border: 1px saddlebrown solid;
        }
        .right{
            width:300px;
            float: right;
            padding-bottom: 10000px;
            margin-bottom: -10000px;
            background:green;
            text-align: center;
            border: 1px saddlebrown solid;
            
            
        }
        h2{
            padding: 10px;
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="left">
           ![](./img/1.png)
           
        </div>
        <div class="right">
           ![](./img/2.png)
        </div>
    </div>
   <button class="btn1">左侧栏增加高度</button>
   <button class="btn2">右侧栏增加高度</button>
    <script src="jquery-3.2.0.min.js"></script>
    <script>
          $('.btn1').on('click',function(){
              $('.left').append('![](./img/1.png)')
          })
          $('.btn2').on('click',function(){
              $('.right').append('![](./img/2.png)')
          })
    </script>
</body>

4. 圣杯布局

  • 思路:
    圣杯布局解决的问题是两边顶宽,中间自适应的三栏布局,中间栏要在放在文档流前面以优先渲染。圣杯布局的三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。解决”中间栏div内容不被遮挡“问题的思路:圣杯布局,为了中间div内容不被遮挡,将中间div设置了左右padding-left和padding-right后,将左右两个div用相对布局position: relative并分别配合right和left属性,以便左右两栏div移动后不遮挡中间div。

  • 重点:

        div{
             float:left;
         }
    .wrap
    {
        padding-right: 100px;//空出左右位置给左右两栏;
        padding-left:100px
    }
    .left
    {
        margin-left: -100%;//左边栏与中间拦并排;
        position: relative;
        left: -100px;//左边的div宽度大小;
    }
    .right
    {
        margin-left: -100px;//右边栏与中间拦并排;大小为右边栏宽度;
        position: relative;
        left: 100px;//左边的div宽度大小;
    }
  • 看下效果:
20170404_172951.gif
  • 代码
 <style>
        .wrap{
            border: 1px saddlebrown solid;
            padding-left:100px;
            padding-right: 100px;
            min-width: 600px;
        }
        .clear:after{
            content:'';
            display: block;
            clear:both;
        }
        .main{
            width:100%;
            height: 200px;
            float:left;
            background:red;
        }
        .left{
            float: left;
            width:100px;
            height: 100px;
            background:green;
            margin-left: -100%;
            position: relative;
            left: -100px;

        }
       .right
               {
        float: left;
        width: 100px;
        height: 100px;
        background: pink;
        margin-left: -100px;
        position: relative;
        left: 100px;
        

    }
    </style>
</head>
<body>
     <div class="wrap clear">
        <div class="main"></div>
        <div class="left"></div>
        <div class="right"></div>
    </div>
</body>

5.双飞翼布局:

  • 思路:
    圣杯布局和双飞翼布局解决的问题是一样的,就是两边顶宽,中间自适应的三栏布局,中间栏要在放在文档流前面以优先渲染。圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。不同在于解决”中间栏div内容不被遮挡“问题的思路不一样;双飞翼布局:为了中间div内容不被遮挡,直接在中间div内部创建子div用于放置内容,在该子div里用margin-left和margin-right为左右两栏div留出位置。

  • 重点:

       .main
       {
        width: 100%;
        float: left;
       }
       .main .mainer//在中间div内部创建子div用于放置内容,在该子div里用margin-left和margin-right为左右两栏div留出位置
    {
        margin-left: 120px;
        margin-right: 120px;
    }
       .left
        {
            float: left;
            margin-left: -100%; //左边栏与中间拦并排;
        }
        .right
        { 
            float: left;
            margin-left: -100px; //右边栏与中间拦并排
        }
  • 看下效果:
20170404_174837.gif
  • 代码:
 .wrap
        {
            border: 1px saddlebrown solid;
            min-width: 600px;
        }
        .clear:after
       {
        content: "";
        display: block;
        clear: both;
       }
       .main
       {
        width: 100%;
        height: 200px;      
        float: left;
     

       }
       .main .mainer
    {
        background: black;
        height: 200px;
        margin-left: 120px;
        margin-right: 120px;

    }
       .left
        {
            width:100px;
            height: 100px;
            background:green;
            float: left;
            margin-left: -100%;
            
        }
        .right
        {
            width: 100px;
            height: 100px;
            background: pink;
            float: left;
            margin-left: -100px;
            
        }

    </style>
</head>
<body>
    <div class="wrap clear">
        <div class="main">
            <div class="mainer"></div>
        </div>
        <div class="left"></div>
        <div class="right"></div>
    </div>
</body>
  • 圣杯双飞翼的区别:

圣杯布局和双飞翼布局解决的问题是一样的,就是两边顶宽,中间自适应的三栏布局,中间栏要在放在文档流前面以优先渲染。圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。不同在于解决”中间栏div内容不被遮挡“问题的思路不一样:圣杯布局,为了中间div内容不被遮挡,将中间div设置了左右padding-left和padding-right后,将左右两个div用相对布局position: relative并分别配合right和left属性,以便左右两栏div移动后不遮挡中间div。双飞翼布局,为了中间div内容不被遮挡,直接在中间div内部创建子div用于放置内容,在该子div里用margin-left和margin-right为左右两栏div留出位置。

6. Flex布局:

Flex布局也是很常用的布局方法可以点击链接去了解下Flex布局方法用法.
Flex布局

7.最后看下jquery实战-无限加载-jsonp-瀑布流

20170405_222202.gif

瀑布流
木桶
等高
圣杯
双飞翼

jquery实战-无限加载-jsonp-瀑布流

希望对给位朋友有所帮助~~~
版权归饥人谷__楠柒所有,如要转载请请注明出处~

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

推荐阅读更多精彩内容