具體原理,參考了騰訊磚牆佈局的思路:http://isux.tencent.com/high-equal-response-layout-html.htmljavascript
等高佈局效果圖:css
如圖,並不像等寬同樣簡單,要在不改變圖片分辨率(寬高比)同時保持等高且佔滿行寬度,如何實現?不妨帶着問題跟我走。html
①行內高度相等;
②行間總寬度相等;
③自適應寬度佈局;
④圖片分辨率(寬高比)不變;java
①行內高度一致,行間高度不一致,可是相差不能太多;
②並不知道一行須要多少個圖片才能佔滿寬度,因爲高度不肯定,圖片的寬度也不能等比變化;
③如何作到自適應?
④佈局用於用戶的我的相冊,數據量是有限且未知的,如何保證圖片數量滿行顯示?jquery
由上可知,這種佈局涉及太多變量,並且最難的是作到圖片分辨率不改變,不影響圖片質量效果。瀏覽器
該以下下手?個人思路是:肯定一個變量,其餘變量根據這個變量作適應性調整。app
①肯定一個變量。因爲當前的瀏覽器寬度是固定的,所以能夠根據瀏覽器寬度範圍制定一個標準高度,相似CSS的媒體查詢(media query);佈局
②初次變換。全部圖片寬度根據這個標準高度做寬度的等比例縮放;flex
③創造容器。每行創建一個div,並裝入儘量多的圖片,直到容器裝不下;ui
④第一步調整。每行根據本身與目標寬度(當前瀏覽器寬度)的差值,再等比例變化寬、高。
公式以下:當前行總寬度/目標寬度=每一個圖片當前高度/變化後高度;
⑤第二步調整。根據變化後高度再等比變化各圖片寬度;
大工告成!然而深刻考慮和分析,還總結出一些別的問題,我用瞭如下不一樣的處理方法把這些問題解決。
①高度調整公式會產生百分比,瀏覽器是會直接取整,所以可能會產生-2到2px的偏差;
解決方法:調整後記錄每行偏差值gap,而後循環把gap的值分給同行每一張圖片,這樣前2張圖片可能會有±1px的圖片寬度變化,可是用戶基本覺察不了圖片的輕微拉伸變化。
②用戶圖片數可能過少,會有圖片只有1-3張佔不滿一行的狀況,該怎樣顯示佈局;
解決方法:判斷只有1行圖片的時候不做佈局調整,少於1行則默認顯示等高變化後的圖片便可(即只調整一次,不須要爲剩餘值再自適應)。
③ 每行調整前的剩餘寬度過大,致使調整後寬高很大;
解決方法:若調整後寬高是原始寬高的150%左右則該行捨棄,這裏考慮到總體圖片質量,確保不影響圖片牆效果。
④ 用戶上傳的照片過小,例如16×16的小圖標,若是同樣的方式調整會與400×800這些圖片並列放大,形成很大縮放比。
解決方法:考慮到是圖片牆的效果,通常不會有用戶傳一些其餘的圖片,例如表情素材等等,同時在圖片處理時能夠加一個排序,獲取了圖片寬高後把小於必定值的圖片排在最後再一塊兒顯示;
按照這個思路,我這裏實現了一個demo,通常狀況下咱們去加載圖片不少時候不知道每一個圖片的寬高值,這裏採用onload加載完成獲取每一個圖片寬高後再去處理的等高佈局。
還有一點區別於以上思路,就是在上面第三步中「解決方法--③創造容器。每行創建一個div,並裝入儘量多的圖片,直到容器裝不下」,這句話是說放不下的時候排列進入下一行展現,我這裏處理成的是進入本行展現。這樣這個標準高度本來如今的是最小高度,而最大高度沒法控制,我這裏改動後這個標準高度就是最大高度,由於我這裏的demo總寬度就這麼大,控制下最大高度比較適合。而若是總寬度較大時用原思路的進入下一行展現的效果也是能夠的。
簡單的demo效果:
頁面代碼 BrickWall.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title>佈局展現</title> 6 <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script> 7 <style> 8 .grid { 9 width: 520px; 10 height: 1000px; 11 overflow: auto; 12 } 13 14 .grid li { 15 list-style-type: none; 16 margin: 0; 17 display: inline-block; 18 } 19 </style> 20 </head> 21 22 <body> 23 <div class="grid"> 24 </div> 25 <script type="text/javascript" src="BrickWall.js"></script> 26 <script> 27 var images = ["images/1.jpg", "images/2.jpg", "images/3.jpg", 28 "images/4.jpg", "images/5.jpg", "images/6.jpg", 29 "images/7.jpg", "images/8.jpg", "images/9.jpg", 30 "images/10.jpg", "images/11.jpg", "images/12.jpg", 31 "images/13.jpg", "images/14.jpg", "images/15.jpg", 32 "images/16.jpg", "images/17.jpg", "images/18.jpg", 33 "images/19.jpg", "images/20.jpg", "images/21.jpg", 34 "images/22.jpg", "images/23.jpg", "images/23.jpg", 35 "images/25.jpg", "images/26.jpg", "images/27.jpg", 36 "images/28.jpg", "images/29.jpg", "images/30.jpg", 37 ]; 38 new BrickWall(document.getElementsByClassName("grid")[0], images, 200, 500, null); 39 </script> 40 </body> 41 42 </html>
js代碼
BrickWall.js文件
1 var BrickWall = (function () { 2 function BrickWall(container, imagesArr, baseHeight, totalWidth, callback) { 3 this.container = container; 4 this.imagesArr = imagesArr; 5 this.baseHeight = baseHeight; 6 this.totalWidth = totalWidth; 7 this.callback = callback; 8 this.imagesObj = []; 9 var imageCount = imagesArr.length; 10 var that = this; 11 imagesArr.forEach(function (src, i) { 12 that.imagesObj[i] = {}; 13 that.imagesObj[i].src = src; 14 var img = document.createElement("img"); 15 img.src = src; 16 that.imagesObj[i].imgEle = img; 17 img.onload = function (e) { 18 that.imagesObj[i].width = img.width * baseHeight / img.height; 19 ; 20 that.imagesObj[i].height = baseHeight; 21 imageCount--; 22 if (imageCount == 0) 23 that.onloadAll(); 24 }; 25 img.onerror = function (e) { 26 imageCount--; 27 if (imageCount == 0) 28 that.onloadAll(); 29 }; 30 }); 31 } 32 //全部圖onload完成後,知道全部的寬高值後才能肯定位置 33 BrickWall.prototype.onloadAll = function () { 34 var that = this; 35 var baseWidth = 0; 36 var divNum = 0; 37 var divTotalWidth = []; 38 that.imagesObj.forEach(function (imgObj, i) { 39 if (baseWidth < that.totalWidth) { 40 baseWidth += imgObj.width; 41 } 42 else { 43 divTotalWidth[divNum] = baseWidth; 44 divNum++; 45 baseWidth = imgObj.width; 46 } 47 imgObj.divNum = divNum; 48 imgObj.imgEle.height = that.baseHeight; 49 imgObj.imgEle.width = imgObj.width; 50 var li = document.createElement("li"); 51 li.appendChild(imgObj.imgEle); 52 that.container.appendChild(li); 53 // var first = that.container.firstChild;//獲得頁面的第一個元素 54 // that.container.insertBefore(li, first);//在獲得的第一個元素以前插入 55 if (i == that.imagesObj.length - 1) 56 divTotalWidth[divNum] = baseWidth; 57 }); 58 that.imagesObj.forEach(function (imgObj, i) { 59 if (divTotalWidth[imgObj.divNum] > that.totalWidth) { 60 imgObj.imgEle.width = that.totalWidth / divTotalWidth[imgObj.divNum] * imgObj.width; 61 imgObj.imgEle.height = that.totalWidth / divTotalWidth[imgObj.divNum] * imgObj.height; 62 } 63 }); 64 }; 65 return BrickWall; 66 }());
另外項目加載圖片須要磚牆佈局,而且是倒序排列,提供如下幾種方法。
1):擴展一個reverse反轉某個元素下子元素的方法
1 $.extend({ 2 reverseChild: function (obj, child) { 3 var childObj = $(obj).find(child); 4 var total = childObj.length; 5 childObj.each(function (i) { 6 $(obj).append(childObj.eq((total - 1) - i)); 7 }); 8 } 9 });
2)使用css
.grid { overflow: auto; display: flex; flex-wrap: wrap-reverse; }
但此時滾動條就失效了,是個問題!
3)在插入列表的時候,每次都插入到列表的第一個位置
1 var li = document.createElement("li"); 2 var first = box.firstChild;//獲得頁面的第一個元素 3 box.insertBefore(li, first);//在獲得的第一個元素以前插入