js+CSS簡單實現瀑布流布局
前言
瀑布流布局,是一種視覺表現為參差不齊的多欄布局。常用于內容以圖片為主的頁面展示,圖片等寬不等高,每行從左到右排滿后,后面的元素依次添加至短的一列其后。隨著頁面向下滾動,還會不斷加載數據并添加到當前尾部,視覺上顯得錯落有致不拘一格。今天使用css和js兩種方式來實現瀑布流布局
css實現瀑布流布局
該方式實現的瀑布流布局其中的內容數據是固定的,主要利用了 CSS 的多列屬性 columns
頁面結構:創(chuàng)建容器container,該容器包裹所有用于展示的元素item(圖片和標題)
<div class="container">
<div class="item">
<img src="..."/>
<h2>...</h2>
</div>
...
</div>
給容器container設置寬度,并居中顯示;控制其中的內容分成3列columns: 3;,列與列之間的距離為20pxcolumn-gap: 20px;
每個item元素,設置屬性break-inside: avoid;, 避免在多列布局中元素內容被分割(元素的內容被自動斷開,圖片在一列尾部,文字在下一列的頭部)
.container {
width: 1200px;
margin: 20px auto;
columns: 3;
column-gap: 20px;
}
.container .item {
width: 100%;
break-inside: avoid;
margin-bottom: 20px;
}
.container .item img{
width: 100%;
}

小結:根據上圖可以看出CSS的多列布局實現的瀑布流是從上到下,再從左到右的順序排列元素,適用于對于元素順序沒有要求,且元素數據固定的情況
js實現瀑布流布局
思路:
每個元素使用絕對定位的方式,動態(tài)的設置相應的top,left值進行排列,先計算一行能夠容納幾列元素,第一行元素直接設置top為0,left為索引乘以(元素寬度 + 間隙)進行排列,后面的元素排列,需要找出所有列中高度最小的那一列,將元素添加至高度最小的那一列后面,直至所有元素添加完畢。
創(chuàng)建一個容器container,用于存放展示的元素。并設置css為相對定位,其中展示的元素為絕對定位
<div id="container"></div>
計算頁面一行能容納幾列元素
列數 = 頁面的寬度 / (元素的寬度+元素之間的間隙 ) column = pageWidth / (itemWidth + gap);
注:頁面的寬度這里設置的是body的寬度(使用css控制了最大寬度和最小寬度)
創(chuàng)建createElement函數,用來動態(tài)創(chuàng)建組成瀑布流的元素塊(包含圖片和標題),并在請求數據成功后調用添加到頁面中,并進行瀑布流布局
function createElement(itemData) {
return new Promise((resolve, reject) => {
let div = document.createElement('div')
div.innerHTML = `...`
div.className = 'item'
// 監(jiān)聽圖片的load事件
div.querySelector('img').addEventListener('load', () => {
resolve(div)
})
})
}
// 獲取喵咪的數據
let page = 1 //請求數據的頁碼
let isReq = false //設置節(jié)流閥,處于請求過程中,則不再請求數據
function loadNewData() {
if (isReq) return
isReq = true
getData()
.then(data => {
// 處理新的數據
let items = data
let promises = items.map(item => createElement(item))
Promise.all(promises).then(nodes => {
let frag = document.createDocumentFragment()
isReq = false
page++
nodes.forEach(node => {
frag.appendChild(node)
Node.push(node)
})
document.getElementById('container').appendChild(frag)
waterfall(Node)
})
})
}
注:遇到獲取元素塊高度不正確的問題
因為圖片可能還沒有完全加載,獲取的元素塊高度就只是h4標簽的高度。因此需要在圖片加載完成后再獲取元素的高度。
a.通過監(jiān)聽圖片的 load 事件,當事件觸發(fā)時,表示圖片已經加載完成,返回創(chuàng)建的div元素
b.在獲取數據loadNewData()函數中,對返回的數據執(zhí)行創(chuàng)建元素方法,并使用Promise.all()對由返回的div元素(Promise 實例)組成的Promise 數組進行處理,當每個Promise實例的狀態(tài)變?yōu)?fulfilled(所有圖片都加載完成),就執(zhí)行瀑布流布局
創(chuàng)建waterfall函數,實現瀑布流
接收元素數組,然后對每個元素進行布局。如果元素在第一行,那么它的頂部位置就是 0,左側位置就是它的索引乘以(元素寬度 + 間隙)。如果元素不在第一行,那么我們首先找出高度最小的列,然后將元素放在這個列的下方,并更新這個列的高度。
function waterfall(items) {
for (var i = loaded; i < items.length; i++) {
let item = items[i]
let height = item.offsetHeight
if (i < columns) {
//滿足這個條件則說明在第一行
item.style.top = 0
item.style.left = (itemWidth + gap) * i + 'px'
heightArr.push(height)
} else {
//其他行,先找出最小高度列的索引
const minIndex = getMinIndex(heightArr)
//top值就是最小列的高度+gap
const top = heightArr[minIndex] + gap
item.style.top = top + 'px'
item.style.left = minIndex * (itemWidth + gap) + 'px'
//修改原本最小列的高度
heightArr[minIndex] = top + height
}
loaded = items.length
}
}
//用于獲取heightArr數組中值最小的列的索引。
const getMinIndex = (array) => {
const min = Math.min.apply(null, array)
return array.indexOf(min)
}
監(jiān)聽頁面滾動,當未顯示的元素內容小于屏幕高度的一大半(這里設置的0.7,因為數據加載比較慢,一般設置成0.5就可以),就需要加載新數據進行展示
window.addEventListener('scroll', lazy)
function lazy() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
const documentHeight = document.documentElement.scrollHeight
// 未顯示的內容 = 文檔(內容)高度-滾動高度-屏幕高度
if (documentHeight - scrollTop - clientHeight < 0.7 * clientHeight) {
loadNewData()
}
}

小結:
a. 簡單封裝的請求數據方法getData()沒有展示出來,請求的接口是從網上找的(地址),一次只能加載10張,并且加載很慢,可以自行查找接口。
b. 需要定義的變量

根據以上基本可以實現瀑布流了,排列順序和滾動頁面加載數據也比較符合一般情況
以上就是js+CSS簡單實現瀑布流布局的詳細內容,更多關于js瀑布流布局的資料請關注腳本之家其它相關文章!
相關文章
javascript仿163網盤無刷新文件上傳系統(tǒng)
這個仿163網盤無刷新文件上傳系統(tǒng),并沒有用使用.net的控件,完全的手工制作。2008-10-10

