zhangxinxu博客的寫法,傳統js寫法css
var waterFall = { container: document.getElementById("container"), //瀑布流容器元素 columnNumber: 1, //瀑布流有多少列 columnWidth: 210, //每一列的寬度 // P_001.jpg ~ P_160.jpg rootImage: "http://cued.xunlei.com/demos/publ/img/", //圖片路徑 indexImage: 0, //圖片序號 scrollTop: document.documentElement.scrollTop || document.body.scrollTop, //頁面滾動距離 detectLeft: 0, loadFinish: false, //是否加載完全部圖片了 // 返回固定格式的圖片名 getIndex: function() { var index = this.indexImage; if (index < 10) { index = "00" + index; } else if (index < 100) { index = "0" + index; } return index; }, // 是否滾動載入的檢測,若是頁面滾動超過某一列的內容,就對這一列執行append方法 appendDetect: function() { var start = 0; for (start; start < this.columnNumber; start++) { var eleColumn = document.getElementById("waterFallColumn_" + start); if (eleColumn && !this.loadFinish) { if (eleColumn.offsetTop + eleColumn.clientHeight < this.scrollTop + (window.innerHeight || document.documentElement.clientHeight)) { this.append(eleColumn); } } } return this; }, // 滾動載入 append: function(column) { this.indexImage += 1; var html = '', index = this.getIndex(), imgUrl = this.rootImage + "P_" + index + ".jpg"; // 圖片尺寸 var aEle = document.createElement("a"); aEle.href = "###"; aEle.className = "pic_a"; aEle.innerHTML = '<img src="'+ imgUrl +'" /><strong>'+ index +'</strong>'; column.appendChild(aEle); if (index >= 160) { //alert("圖片加載光光了!"); this.loadFinish = true; } return this; }, // 頁面加載初始建立 create: function() { this.columnNumber = Math.floor(document.body.clientWidth / this.columnWidth); //根據body寬度和一列的寬度計算出有多少列 var start = 0, htmlColumn = '', self = this; for (start; start < this.columnNumber; start+=1) { htmlColumn = htmlColumn + '<span id="waterFallColumn_'+ start +'" class="column" style="width:'+ this.columnWidth +'px;">'+ function() { var html = '', i = 0; for (i=0; i<5; i+=1) { self.indexImage = start + self.columnNumber * i; var index = self.getIndex(); html = html + '<a href="###" class="pic_a"><img src="'+ self.rootImage + "P_" + index +'.jpg" /><strong>'+ index +'</strong></a>'; } return html; }() + '</span> '; //循環建立每一列,每一列初始化就先填入5張圖片 } htmlColumn += '<span id="waterFallDetect" class="column" style="width:'+ this.columnWidth +'px;"></span>'; //這個塊用於檢測是否頁面的寬度發生變化,是否須要觸發refresh操做 this.container.innerHTML = htmlColumn; this.detectLeft = document.getElementById("waterFallDetect").offsetLeft; return this; }, refresh: function() { var arrHtml = [], arrTemp = [], htmlAll = '', start = 0, maxLength = 0; for (start; start < this.columnNumber; start+=1) { var arrColumn = document.getElementById("waterFallColumn_" + start).innerHTML.match(/<a(?:.|\n|\r|\s)*?a>/gi); if (arrColumn) { maxLength = Math.max(maxLength, arrColumn.length); // arrTemp是一個二維數組 arrTemp.push(arrColumn); } } //佈局從新變化的時候先把全部已經加載好的圖片按照列存在二維數組裏 // 須要從新排序 二維數組從左到右,從上到下,把分散在各個列裏的圖片塊再次按照順序連成一個數組 var lengthStart, arrStart; for (lengthStart = 0; lengthStart<maxLength; lengthStart++) { for (arrStart = 0; arrStart<this.columnNumber; arrStart++) { if (arrTemp[arrStart][lengthStart]) { arrHtml.push(arrTemp[arrStart][lengthStart]); } } } if (arrHtml && arrHtml.length !== 0) { // 新欄個數 this.columnNumber = Math.floor(document.body.clientWidth / this.columnWidth); // 計算每列的行數 // 向下取整 var line = Math.floor(arrHtml.length / this.columnNumber); // 從新組裝HTML var newStart = 0, htmlColumn = '', self = this; for (newStart; newStart < this.columnNumber; newStart+=1) { htmlColumn = htmlColumn + '<span id="waterFallColumn_'+ newStart +'" class="column" style="width:'+ this.columnWidth +'px;">'+ function() { var html = '', i = 0; for (i=0; i<line; i+=1) { html += arrHtml[newStart + self.columnNumber * i]; } // 是否補足餘數 html = html + (arrHtml[newStart + self.columnNumber * line] || ''); return html; }() + '</span> '; } htmlColumn += '<span id="waterFallDetect" class="column" style="width:'+ this.columnWidth +'px;"></span>'; this.container.innerHTML = htmlColumn; this.detectLeft = document.getElementById("waterFallDetect").offsetLeft; // 檢測 this.appendDetect(); } return this; }, // 滾動加載 scroll: function() { var self = this; window.onscroll = function() { // 爲提升性能,滾動先後距離大於100像素再處理 var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; if (!this.loadFinish && Math.abs(scrollTop - self.scrollTop) > 100) { self.scrollTop = scrollTop; self.appendDetect(); } }; return this; }, // 瀏覽器窗口大小變換 resize: function() { var self = this; window.onresize = function() { var eleDetect = document.getElementById("waterFallDetect"), detectLeft = eleDetect && eleDetect.offsetLeft; if (detectLeft && Math.abs(detectLeft - self.detectLeft) > 50) { // 檢測標籤偏移異常,認爲佈局要改變 self.refresh(); } }; return this; }, init: function() { if (this.container) { this.create().scroll().resize(); } } }; waterFall.init();
其餘方法html
Multi-columns多列布局數組
html:瀏覽器
<div class="masonry"> <div class="item"> <div class="item__content"> </div> </div> <div class="item"> <div class="item__content"> </div> </div> <!-- more items --> </div>
css:app
.masonry { column-count: 5; column-gap: 0; }
瀑布流容器分紅5列,列與列之間的間距是0。ide
使用多列布局的關鍵在於內容的中斷(break),中斷有三種,page-break,column-break,region-break。佈局
爲了阻止內容的中斷,避免內容的一部分被截斷到了下一列,這裏必須使用break-inside。性能
.item { break-inside: avoid; box-sizing: border-box; padding: 10px; }
設置break-indide:avoid;後,每個item元素都能完整顯示,內容不會再被截斷致使跨列了。flex
藉助媒體查詢,在不一樣寬度頁面狀況下,列數不一樣:this
.masonry { column-count: 1; // one column on mobile } @media (min-width: 400px) { .masonry { column-count: 2; // two columns on larger phones } } @media (min-width: 1200px) { .masonry { column-count: 3; // three columns on...you get it } } <!-- etc. -->
這樣就使用多列布局實現了瀑布流,純css實現。
flexbox彈性盒佈局
html:
<div class="masonry"> <div class="column"> <div class="item"> <div class="item__content"> </div> </div> <!-- more items --> </div> <div class="column"> <div class="item"> <div class="item__content"> </div> </div> <!-- more items --> </div> <div class="column"> <div class="item"> <div class="item__content"> </div> </div> <!-- more items --> </div> </div>
css:
.masonry { display: flex; flex-direction: row; } .column { display: flex; flex-direction: column; width: calc(100%/3); }
將masonry盒子和column盒子都設置爲flex,masonry的方向設置爲行,而column設置爲列。
每一列的寬度經過calc()來計算。
還須要媒體查詢來控制不一樣寬度頁面的效果:
.masonry { display: flex; flex-direction: column; } @media only screen and (min-width: 500px) { .masonry { flex-direction: row; } } .column { display: flex; flex-flow: column wrap; width: 100%; } @media only screen and (min-width: 500px) { .column { width: calc(100%/5); } }
當頁面寬度小於500px的時候,masonry盒子方向變爲列,所有變成一列顯示;當頁面寬度大於500px的時候,masonry盒子方向變爲行,一行中的每一列的寬度是calc(100%/5),變成5列顯示。
實際效果: