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

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

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

根據(jù)以上基本可以實現(xiàn)瀑布流了,排列順序和滾動頁面加載數(shù)據(jù)也比較符合一般情況
以上就是js+CSS簡單實現(xiàn)瀑布流布局的詳細(xì)內(nèi)容,更多關(guān)于js瀑布流布局的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
利用javascript的面向?qū)ο蟮奶匦詫崿F(xiàn)限制試用期
Javascript是一種面向?qū)ο蟮哪_本語言,其也具有面向?qū)ο蟮娜筇匦裕墙裉煳覀儾辉敿?xì)的講解javascript的面向?qū)ο筇匦?,今天我們簡單的了解一下javascript的面向?qū)ο筇匦裕缓髮W(xué)習(xí)一下怎樣實現(xiàn)試用期的限制!2011-08-08
js從10種顏色中隨機(jī)取色實現(xiàn)每次取出不同的顏色
昨天在做js 從10種顏色中隨機(jī)取色,并每次取出的顏色不同,具體的實現(xiàn)思路如下,感興趣的朋友可以參考下2013-10-10
javascript仿163網(wǎng)盤無刷新文件上傳系統(tǒng)
這個仿163網(wǎng)盤無刷新文件上傳系統(tǒng),并沒有用使用.net的控件,完全的手工制作。2008-10-10
javascript css紅色經(jīng)典選項卡效果實現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了javascript css紅色經(jīng)典選項卡效果的實現(xiàn)代碼,需要的朋友可以參考下2016-05-05

