最近在整理js基礎知識,接觸到了幾個經常使用的頁面特效,其中以爲用原生js實現瀑布流的案例十分有趣,因而與你們分享一下。html
瀑布流,又稱瀑布流式佈局。是比較流行的一種網站頁面佈局,視覺表現爲良莠不齊的多欄佈局,隨着頁面滾動條向下滾動,這種佈局還會不斷加載數據塊並附加至當前尾部。
一、首先瀑布流全部的圖片應該保持寬度一致,高度是由內容決定。ajax
左浮動的話,咱們能夠看到第6
個盒子直接就在第4
個盒子旁邊停下了,由於第4
個高度最高,擋住了它左浮動的去路。第6
個盒子是第2
行的最後一個,因此第7
個盒子只能在第3
行排列了。當排到第12
個盒子的時候,盒子會以第11
個盒子的位置爲基礎左浮動(這就是第12
個盒子爲何沒有‘跳到’第9
個盒子下面的緣由),碰到第8
個盒子後又被擋住了。數組
經過定位的方式是咱們實現瀑布流的最基本的原理,只要咱們動態的設置它的top
值、left
值,就能讓它排列。瀏覽器
二、定位後肯定瀏覽器顯示區域內,一行能放多少列圖片盒子。app
column = pageWidth / itemWidth
三、爲了美觀咱們能夠加上一個空隙函數
column = pageWidth / (itemWidth + gap);
四、 肯定列數以後,排列第一行佈局
1
行,因此在for
循環裏就要判斷一下,當i
(全部圖片盒子的索引) < column
(顯示列數)的時候,說明在第1
行;1
行以後,動態設置每一個圖片盒子的left
值就能排好第1
行。left = i * ( itemWidth + gap );
五、第1行排列好以後,獲取第1行全部圖片盒子的高度網站
arr
,將獲取到的高度存在數組中,由於第2
行排列的時候須要考慮top
值,此時只能根據第1
行圖片盒子的高度來設置;onload
裏面,由於圖片的加載特性是:等頁面都加載完以後纔去請求加載,因此不寫在入口函數裏可能會出現高度獲取不到的狀況。六、排列第2行spa
2
行的第1
個圖片盒子放置在它的下方;left
值就是高度最小列的offsetLeft
;top
值就是:第1
行高度最小列的高度(爲了佈局美觀能夠加上上下間隙gap
)。index
,後面計算會用到;七、改變最小列當前高度code
八、觸發resize事件
onload
裏面註冊一個resize
事件,只要頁面一發生改變,就觸發樣式部分的代碼。pageWidth
的寬度,這樣瀑布流就會是一個響應式的效果了九、懶加載效果
30
張圖片,假如一個頁面中有幾百張圖片的時候,咱們不可能等到它都加載完再顯示,全部這裏引入一個懶加載的概念,咱們規定第30
張爲顯示的最後一張圖片,當滾動條滾動到30
張的時候,應該加載下一批圖片。30
圖片的offsetTop
;的時候加載下面的圖片。完整代碼:
<!-- 樣式部分 --> <style> * { margin: 0; padding: 0; position: relative; } img { width: 220px; display: block; } .item { box-shadow: 2px 2px 2px #999; position: absolute; } </style> <!-- html 部分 --> <div id="box"> <div class="item"><img src="../image/瀑布流/001.jpg" alt=""></div> . . . <div class="item"><img src="../image/瀑布流/030.jpg" alt=""></div> </div> <!-- js 部分 --> <script> var box = document.getElementById('box'); var items = box.children; // 定義每一列之間的間隙 爲10像素 var gap = 10; window.onload = function() { // 一進來就調用一次 waterFall(); // 封裝成一個函數 function waterFall() { // 1- 肯定列數 = 頁面的寬度 / 圖片的寬度 var pageWidth = getClient().width; var itemWidth = items[0].offsetWidth; var columns = parseInt(pageWidth / (itemWidth + gap)); var arr = []; for (var i = 0; i < items.length; i++) { if (i < columns) { // 2- 肯定第一行 items[i].style.top = 0; items[i].style.left = (itemWidth + gap) * i + 'px'; arr.push(items[i].offsetHeight); } else { // 其餘行 // 3- 找到數組中最小高度 和 它的索引 var minHeight = arr[0]; var index = 0; for (var j = 0; j < arr.length; j++) { if (minHeight > arr[j]) { minHeight = arr[j]; index = j; } } // 4- 設置下一行的第一個盒子位置 // top值就是最小列的高度 + gap items[i].style.top = arr[index] + gap + 'px'; // left值就是最小列距離左邊的距離 items[i].style.left = items[index].offsetLeft + 'px'; // 5- 修改最小列的高度 // 最小列的高度 = 當前本身的高度 + 拼接過來的高度 + 間隙的高度 arr[index] = arr[index] + items[i].offsetHeight + gap; } } } // 頁面尺寸改變時實時觸發 window.onresize = function() { waterFall(); }; // 當加載到第30張的時候 window.onscroll = function() { if (getClient().height + getScrollTop() >= items[items.length - 1].offsetTop) { // 模擬 ajax 獲取數據 var datas = [ "../image/瀑布流/001.jpg", ... "../image/瀑布流/030.jpg" ]; for (var i = 0; i < datas.length; i++) { var div = document.createElement("div"); div.className = "item"; div.innerHTML = '<img src="' + datas[i] + '" alt="">'; box.appendChild(div); } waterFall(); } }; }; // clientWidth 處理兼容性 function getClient() { return { width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight } } // scrollTop兼容性處理 function getScrollTop() { return window.pageYOffset || document.documentElement.scrollTop; } </script>
效果圖: