[关闭]
@EncyKe 2015-12-29T15:45:47.000000Z 字数 5834 阅读 1741

JS:瀑布流布局

JavaScript 前端



零、简介

  1. 特点:多栏、不断加载、单页、每一栏等宽;
  2. 示例:Pinterest花瓣网、蘑菇街、美丽说;

一、JS原生方法

1. HTML

  1. <div id="main">
  2. <div class="pin">
  3. <div class="box">
  4. <img src="" />
  5. </div>
  6. </div>
  7. </div>

2. CSS

  1. *{padding: 0;margin:0;}
  2. #main{
  3. position: relative;
  4. }
  5. .pin{
  6. padding: 15px 0 0 15px;
  7. float:left;
  8. }
  9. .box{
  10. padding: 10px;
  11. border:1px solid #ccc;
  12. box-shadow: 0 0 6px #ccc;
  13. border-radius: 5px;
  14. }
  15. .box img{
  16. width:162px;
  17. height:auto;
  18. }

3. JS

  1. window.onload=function(){
  2. waterfall('main','pin');
  3. // 模拟JSON后台数据获取
  4. var dataInt = {
  5. 'data':[
  6. {'src':'0.jpg'},
  7. {'src':'1.jpg'},
  8. {'src':'2.jpg'},
  9. {'src':'3.jpg'},
  10. {'src':'4.jpg'},
  11. {'src':'5.jpg'},
  12. {'src':'6.jpg'},
  13. {'src':'7.jpg'},
  14. {'src':'8.jpg'},
  15. {'src':'9.jpg'}
  16. ]
  17. };
  18. // ==========================================================
  19. // 鼠标滚动加载事件
  20. // ==========================================================
  21. window.onscroll = function(){
  22. if(checkscrollside()){
  23. // 获取父级对象
  24. var oParent = document.getElementById('main');
  25. for(var i = 0; i < dataInt.data.length; i++){
  26. //添加div.pin
  27. var oPin = document.createElement('div');
  28. oPin.className = 'pin';
  29. oParent.appendChild(oPin);
  30. //添加div.box
  31. var oBox = document.createElement('div');
  32. oBox.className = 'box';
  33. oPin.appendChild(oBox);
  34. //添加img
  35. var oImg = document.createElement('img');
  36. oImg.src = './images/'+dataInt.data[i].src;
  37. oBox.appendChild(oImg);
  38. }
  39. waterfall('main','pin');
  40. };
  41. }
  42. }
  43. // ==========================================================
  44. // 瀑布流主函数
  45. // ==========================================================
  46. function waterfall(parent,pin){
  47. // 通过父级获取数据块对象集合aPin
  48. var oParent = document.getElementById(parent);
  49. var aPin = getClassObj(oParent,pin);
  50. // 获取单个块pin的宽
  51. var iPinW = aPin[0].offsetWidth;
  52. // 计算整个页面的列数
  53. var num = Math.floor(document.documentElement.clientWidth/iPinW);
  54. // 设置父级居中样式:定宽+自动水平外边距
  55. oParent.style.cssText = 'width:' + iPinW * num + 'px;ma rgin:0 auto;';
  56. // 用于存储每列中的所有块相加的高度。
  57. var pinHArr = [];
  58. // 遍历数组aPin的每个块元素
  59. for(var i = 0; i < aPin.length; i++){
  60. var pinH = aPin[i].offsetHeight;
  61. if(i < num){
  62. // 把第一行中的num个块pin先添加进数组pinHArr
  63. pinHArr[i] = pinH;
  64. }else{
  65. // 获取数组pinHArr中的最小值minH
  66. var minH = Math.min.apply(null,pinHArr);
  67. var minHIndex = getminHIndex(pinHArr,minH);
  68. // 设置绝对位移
  69. aPin[i].style.position = 'absolute';
  70. aPin[i].style.top = minH + 'px';
  71. aPin[i].style.left = aPin[minHIndex].offsetLeft + 'px';
  72. // 数组中最小高高度 + 新添的aPin[i]块高,更新添加了块后的列高
  73. pinHArr[minHIndex] += aPin[i].offsetHeight;
  74. }
  75. }
  76. }
  77. // ==========================================================
  78. // 封装getClassObj(),通过父级获取类
  79. // ==========================================================
  80. function getClassObj(parent,className){
  81. // 获取父级的所有子集
  82. var obj=parent.getElementsByTagName('*');
  83. // 创建一个数组 用于收集子元素
  84. var pinS=[];
  85. // 遍历子元素、判断类别、压入数组
  86. for (var i=0;i<obj.length;i++) {
  87. if (obj[i].className==className){
  88. pinS.push(obj[i]);
  89. }
  90. };
  91. return pinS;
  92. }
  93. // ==========================================================
  94. // 获取pin高度最小的索引index
  95. // ==========================================================
  96. function getminHIndex(arr,minH){
  97. for(var i in arr){
  98. if(arr[i]==minH){
  99. return i;
  100. }
  101. }
  102. }
  103. // ==========================================================
  104. // 检测是否具备滚动加载数据块的条件
  105. // ==========================================================
  106. function checkscrollside(){
  107. var oParent = document.getElementById('main');
  108. var aPin = getClassObj(oParent,'pin');
  109. // 最后一个块框的距离页面顶端+自身高的一半(实现未滚到底就开始加载)
  110. var lastPinH = aPin[aPin.length-1].offsetTop + Math.floor(aPin[aPin.length-1].offsetHeight/2);
  111. // 获取视界顶端到页面顶端的距离
  112. var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  113. // 获取视界高度
  114. var documentH = document.documentElement.clientHeight;
  115. // 到达指定高度后,返回true,触发waterfall()函数
  116. return (lastPinH < scrollTop + documentH) ? true : false;
  117. }

二、jQuery方法

1. HTML与CSS部分

2. JS部分

  1. $(window).on("load", function(){
  2. waterfall('main','pin');
  3. var dataInt = {
  4. 'data':[
  5. {'src':'0.jpg'},
  6. {'src':'1.jpg'},
  7. {'src':'2.jpg'},
  8. {'src':'3.jpg'},
  9. {'src':'4.jpg'},
  10. {'src':'5.jpg'},
  11. {'src':'6.jpg'},
  12. {'src':'7.jpg'},
  13. {'src':'8.jpg'},
  14. {'src':'9.jpg'}
  15. ]
  16. };
  17. window.onscroll=function(){
  18. if(checkscrollside()){
  19. $.each( dataInt.data, function(index, value){
  20. var $oPin = $('<div>').addClass('pin').appendTo($("#main"));
  21. var $oBox = $('<div>').addClass('box').appendTo($oPin);
  22. $('<img>').attr('src','./images/' + $(value).attr('src')).appendTo($oBox);
  23. });
  24. waterfall();
  25. };
  26. }
  27. });
  28. function waterfall(parent,pin){
  29. var $aPin = $( "#main>div" );
  30. // 获取一个块pin的宽
  31. var iPinW = $aPin.eq(0).outerWidth();
  32. // 一行中的列数【窗口宽度除以一个块框宽度】
  33. var num = Math.floor($(window).width() / iPinW);
  34. // 设置父级居中样式:定宽+自动水平外边距
  35. // oParent.style.cssText='width:'+iPinW*num+'px;margin:0 auto;';
  36. $("#main").css({
  37. 'width:' : iPinW * num,
  38. 'margin': '0 auto'
  39. });
  40. // 用于存储每列中的所有块框相加的高度。
  41. var pinHArr=[];
  42. $aPin.each(function(index, value){
  43. var pinH = $aPin.eq(index).outerHeight();
  44. if(index < num){
  45. // 把第一行中的num个块pin先添加进数组pinHArr
  46. pinHArr[index] = pinH;
  47. }else{
  48. // 获取数组pinHArr中的最小值minH
  49. var minH = Math.min.apply(null, pinHArr);
  50. var minHIndex = $.inArray(minH, pinHArr);
  51. $(value).css({
  52. 'position': 'absolute',
  53. 'top': minH,
  54. 'left': $aPin.eq(minHIndex).position().left
  55. });
  56. //数组中最小高元素的高 + 添加上的aPin[i]块框高,更新添加了块框后的列高
  57. pinHArr[ minHIndex ] += $aPin.eq(index).outerHeight();
  58. }
  59. });
  60. }
  61. function checkscrollside(){
  62. var $aPin = $( "#main>div" );
  63. var lastPinH = $aPin.last().get(0).offsetTop + Math.floor($aPin.last().height()/2);
  64. var scrollTop = $( window ).scrollTop()
  65. var documentH = $( document ).width();
  66. return (lastPinH < scrollTop + documentH ) ? true : false;
  67. }

三、CSS3方法

1. HTML部分

2. CSS3部分

  1. *{padding: 0;margin:0;}
  2. #main{
  3. position: relative;
  4. -webkit-column-width:230px;
  5. -moz-column-width:230px;
  6. -ms-column-width:230px;
  7. -o-column-width:230px;
  8. column-width:230px;
  9. -webkit-column-gap:5px;
  10. -moz-column-gap:5px;
  11. -ms-column-gap:5px;
  12. -o-column-gap:5px;
  13. column-gap: 5px;
  14. }
  15. .pin{
  16. padding: 15px 0 0 15px;
  17. float:left;
  18. }
  19. .box{
  20. padding: 10px;
  21. border:1px solid #ccc;
  22. box-shadow: 0 0 6px #ccc;
  23. border-radius: 5px;
  24. }
  25. .box img{
  26. width:230px;
  27. height:auto;
  28. }

优点:性能略优、代码量少、无需计算;
缺点:兼容性差、列宽变化、图片顺序竖排、体验不佳、图片加载仍需JS协助;

附:参考

慕课:瀑布流布局
Demo下载

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注