瀑布流式布局(解決div等寬不等高,實現緊挨效果)


 

為什么要有瀑布流:

由於div高度不一樣,不管是左浮動還是inline-block,同級的div都會平行顯示(會有空白部分)。

 

沒有加的效果:

 

 

加了瀑布流效果樣子:

 

 

瀑布流實現方式:

1. css + js (難點) :  需要通過js計算圖片的位置,進行正確排放,順序不會亂,可持續加載新的數據

2. 純css(簡單) : 數據排序方式是列排序的,當有新的數據持續加載進入不合適,但是性能高、簡單

 

視頻教程:

# 慕課網的 瀑布流布局教程視頻

https://www.imooc.com/learn/101

 

第一種方法:

思路: 首先瀑布流的特點是 等寬不等高,需要獲取到盒子的寬度,計算出多少列,拿到第一行每個盒子的高度數組,從第二行第一個開始,依次找最矮盒子的高度位置進行位置偏移即可,之后累加列高度,從而使整個頁面的盒子緊挨。

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4   <meta charset="UTF-8">
  5   <title>Title</title>
  6   <style>
  7     body{
  8       padding: 0;
  9       margin: 0;
 10     }
 11     #pb_main{
 12       position: relative;
 13     }
 14     #pb_main .box{
 15       width: 15.6%;
 16       padding: 0.5em;
 17       float: left;
 18     }
 19     #pb_main .box .box-content{
 20       border: 1px solid #aaa;
 21       border-radius: 1em;
 22       overflow: hidden;
 23       box-shadow: 0 0 20px #ccc;
 24     }
 25     #pb_main .box .box-content:hover{
 26       cursor: pointer;
 27       transition: 0.2s;
 28       transform: translateY(-5px);
 29     }
 30     #pb_main .box .box-content .picture{
 31     }
 32     #pb_main .box .box-content .picture img{
 33       width: 100%;
 34     }
 35     #pb_main .box .box-content .pb-text{
 36       padding: 5px;
 37     }
 38 
 39   </style>
 40 </head>
 41 <body>
 42   
 43   <div id="pb_main">
 44 
 45   </div>
 46 
 47 <script>
 48 
 49   let img_index = 0;
 50 
 51   // 批量添加一些,第一批測試數據
 52   function addElement(count) {
 53     let pb_main = document.getElementById('pb_main');
 54     for (let i=0;i<count;i++,img_index++){
 55       let box = document.createElement('div');
 56       box.classList.add('box');
 57       let boxContent = document.createElement('div');
 58       boxContent.classList.add('box-content');
 59       let picture = document.createElement('div');
 60       picture.classList.add('picture');
 61       let img = document.createElement('img');
 62       img.src = `image/${img_index+1}.jpg`;
 63       let pgText = document.createElement('div');
 64       pgText.classList.add('pb-text');
 65       pgText.innerText = `${(i+1)*123}測試標題~~`;
 66 
 67       picture.appendChild(img);
 68       boxContent.appendChild(picture);
 69       boxContent.appendChild(pgText);
 70       box.appendChild(boxContent);
 71       pb_main.appendChild(box);
 72 
 73       // 每加載好一個圖片,就執行重新布局一遍。
 74       img.onload = function () {
 75         waterfall('pb_main', 'box')
 76       };
 77     }
 78 
 79   }
 80 
 81   function getArrayIndex(arr, value) {
 82     for (let i=0;i<arr.length;i++){
 83       if (arr[i] === value){
 84         return i;
 85       }
 86     }
 87   }
 88 
 89   // 排版瀑布流,思路:第二行第一個元素跟着第一行高度最矮的,依次類推。
 90   function waterfall(parent, box){
 91     // 獲取標簽對象
 92     let Parent = document.getElementById(parent);
 93     let boxes = Parent.getElementsByClassName(box);
 94     // 獲取盒子的寬,瀑布流的特點:等寬不等高
 95     let boxWidth = boxes[0].offsetWidth;
 96     // 獲取屏幕能有幾列盒子數
 97     let cols = Math.floor(document.body.clientWidth / boxWidth);
 98     // 存放列高
 99     let temp = [];
100     // 循環修改盒子的位置
101     for (let i=0;i<boxes.length;i++){
102       // 第一行不做位置修改,要記錄高度,再后續行修改完位置后需要累加高度
103       // 第二行、第三行。。。根據temp表里記錄的高度,找出最矮的依次排序到下面
104       if (i < cols){
105         temp.push(boxes[i].offsetHeight);
106       }else{
107         // 查找最小的高度
108         let height = Math.min(...temp);
109         // 最小高度的索引
110         let index = getArrayIndex(temp, height);
111         // 修改當前循環盒子的頁面位置
112         boxes[i].style.position = "absolute";
113         boxes[i].style.left = `${boxWidth * index}px`;
114         boxes[i].style.top = `${height}px`;
115         // 累加高度列表的該索引的值
116         temp[index] += boxes[i].offsetHeight;
117         // 設置父級高度,這樣布局不會亂,由於左浮動后沒有高度
118         Parent.style.height = `${Math.max(...temp)}px`
119       }
120     }
121   }
122 
123   // 檢查高度是否超過
124   function checkScrollTop(parent, box){
125     // 滾動條頂部的值
126     let top = document.documentElement.scrollTop||document.body.scrollTop;
127     let screen_height = document.documentElement.clientHeight || document.body.clientHeight;
128     // 獲取標簽對象
129     let Parent = document.getElementById(parent);
130     let boxes = Parent.getElementsByClassName(box);
131     let last_box = boxes[boxes.length-1];
132     let last_box_h = last_box.offsetTop + Math.floor(last_box.offsetHeight / 2);
133     console.log(`最后盒子頂部距離 + 它一半高度:${last_box_h}, 頂部距離加屏幕高度是: ${top+screen_height}`);
134     // 判斷頂部滾輪+屏幕高度是否大於這個最后盒子距離+一半高度, 大於表示要加載新內容了
135     return (top+screen_height) > last_box_h  ? true:false;
136   }
137 
138   window.onload = function (){
139     // 添加首次的測試元素,需要大於一屏幕
140     addElement(20);
141     // 監測滾動條
142     window.onscroll = function () {
143       // 判讀是否需要加載新內容
144       if (checkScrollTop('pb_main', 'box')){
145         addElement(10);
146         // 由於圖片有限,重置
147         if (img_index >= 29){
148           img_index = 0;
149         }
150       }
151     }
152   }
153 
154 </script>
155 </body>
156 </html>
View Code

// 圖片素材自己找點(30張圖片),就可以看運行效果了

 

第二種方法:

  .my-card-wrapper{ -moz-column-count:2; -webkit-column-count:2; column-count:2; -moz-column-gap:0; -webkit-column-gap:0;
    padding-top: 0.5em;
  }


  .my-card{
    border: 1px solid #cccccc;
    padding: 8px;
    border-radius: 10px;
    -moz-page-break-inside: avoid; -webkit-column-break-inside: avoid; break-inside: avoid;
    margin: 0 0.5em 0.5em;
  }

// 斜體加粗部分是關鍵代碼

 

 代碼解釋:

column-count   # 流式布局幾列顯示
-moz-column-count:2;     # 為了適配不同瀏覽器
-webkit-column-count:2;  # 為了適配不同瀏覽器
-webkit-column-gap:0;  # 列之前的間隔,有默認間隔值,為了不影響效果,我改的0,自己做邊距
break-inside: avoid;  # 防止多列布局,分頁媒體和多區域上下文中的意外中斷?? 不懂設置上即可
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM