JavaScript實(shí)現(xiàn)瀑布流布局詳解
需求
所謂瀑布流布局,就是含有若干個(gè)等寬的列,每一列分別放置圖片、視頻等,放置的元素都是等寬的,因此可能是不等高的。新的元素到來(lái)時(shí),會(huì)插入高度較低的那一列,這樣形成參差的、視覺(jué)上像瀑布一樣的布局。
這里簡(jiǎn)化一下,只要兩列等寬布局展示圖片即可。
思路
兩列布局,直接使用flex布局實(shí)現(xiàn)即可。不過(guò),這里不能設(shè)置align-items為center,如果設(shè)置了將會(huì)使圖片列居中顯示,不符合瀑布流的視覺(jué)效果。我設(shè)置left和right兩列,兩列的寬度相等,結(jié)構(gòu)和樣式基本就寫(xiě)完了。
然后寫(xiě)JavaScript。其邏輯是,判斷當(dāng)前l(fā)eft和right的高度(我使用clientHeight),如果左邊<=右邊,則放入左邊,否則放入右邊。遍歷所有的圖片,按照這個(gè)邏輯放入即可。
代碼實(shí)現(xiàn)
html部分
<!-- 瀑布流父容器 --> <div class="container"> <!-- 兩列等寬布局 --> <div class="col left"></div> <div class="col right"></div> </div>
css部分
.container { width: 700px; background-color: aliceblue; margin: auto; /* flex布局 */ display: flex; align-items: flex-start; } .col { flex-basis: 350px; } .col img { /* 固定圖片的寬度 */ width: 100%; }
JavaScript部分
// 獲取三個(gè)元素 let container = document.getElementsByClassName('container')[0] let left = document.getElementsByClassName('col')[0] let right = document.getElementsByClassName('col')[1] // 插入圖片 function initImg() { for (let i = 1; i < 27; i++) { let img = new Image(); img.src = "./pictures/" + i + ".jpg" if (left.clientHeight <= right.clientHeight) { left.appendChild(img) } else { right.appendChild(img) } } } initImg()
如代碼所示,獲取了父元素和左右兩列,然后遍歷每一張圖片,依次判斷插入即可。看上去很完美,但是真的如此嗎?
實(shí)現(xiàn)效果
看上去貌似很完美,也有瀑布的樣子。但當(dāng)拉到頁(yè)面底部發(fā)現(xiàn):
左邊的一大塊都是空的,全部放在了右邊。這顯然不對(duì),因?yàn)榘凑者壿?,左邊更短,?yīng)該加在左邊才對(duì)。
問(wèn)題和修正
問(wèn)題就在于,img的加載是個(gè)異步的過(guò)程。再看剛才的for循環(huán):
// 插入圖片 function initImg() { for (let i = 1; i < 27; i++) { let img = new Image(); img.src = "./pictures/" + i + ".jpg" if (left.clientHeight <= right.clientHeight) { left.appendChild(img) } else { right.appendChild(img) } } }
new了Image對(duì)象后,指定了其src,然后立刻判斷左右兩邊的高度。這時(shí),img還沒(méi)有加載完畢。然而,for循環(huán)不會(huì)等待它加載完畢。下一張圖片產(chǎn)生后,立刻也會(huì)判斷,但此時(shí)上一張圖片還沒(méi)有放到頁(yè)面上,所以左右的高度很可能就是錯(cuò)誤的,從而產(chǎn)生了錯(cuò)誤的判斷。這就出現(xiàn)了上圖中,右列出現(xiàn)了很多很多圖片,而左列空白的樣子。
解決辦法就是,把這個(gè)循環(huán)寫(xiě)成異步的,只有上一張圖片加載完畢后,才去判斷下一張圖片。
很容易想到,使用Promise完成異步判斷。但是對(duì)于循環(huán)中的Promise,很難清楚地通過(guò)then的變化來(lái)推進(jìn)。于是,我決定采用async和await。
這就需要再封裝一個(gè)方法,這個(gè)方法返回Promise,在Promise中加載某一張圖片。然后再遍歷所有圖片,使用async/await,依次調(diào)用這個(gè)方法,就能得到結(jié)果了。
而在Promise中,我們?cè)谑裁磿r(shí)候調(diào)用resolve呢?這就需要監(jiān)聽(tīng)img的onload事件,設(shè)置onload事件的回調(diào)函數(shù),在回調(diào)函數(shù)中調(diào)用resolve即可。
經(jīng)過(guò)分析,再次完善代碼:
// 加載第index張圖片 function loadIndexImg(index) { return new Promise((resolve, reject) => { // 當(dāng)前加載的圖片 let img = new Image(); img.src = './pictures/' + index + '.jpg' img.onload = () => { if (left.clientHeight <= right.clientHeight) { left.appendChild(img) } else { right.appendChild(img) } resolve(); } }) } // 插入圖片 async function initImg() { // 要在加載完并插入圖片后才去判斷下一張,因此采用async/await for (let i = 1; i <= 26; i++) { await loadIndexImg(i) } } initImg()
可以看到,在initImg中,依次調(diào)用loadIndexImg,并且是異步調(diào)用。在圖片加載完成后再去加載下一張圖片,效果應(yīng)該就可以了。
修正后效果
效果很好?。?!
總結(jié)
本文實(shí)現(xiàn)了簡(jiǎn)單的兩列瀑布流布局,其中需要用到Promise等異步操作。
到此這篇關(guān)于JavaScript實(shí)現(xiàn)瀑布流布局詳解的文章就介紹到這了,更多相關(guān)JS瀑布流布局內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信小程序?qū)崿F(xiàn)五星評(píng)價(jià)功能
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)五星評(píng)價(jià)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08通過(guò)JS判斷聯(lián)網(wǎng)類型和連接狀態(tài)的實(shí)現(xiàn)代碼
這篇文章主要介紹了通過(guò)JS判斷聯(lián)網(wǎng)類型和連接狀態(tài)的實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04微信JS-SDK自定義分享功能實(shí)例詳解【分享給朋友/分享到朋友圈】
這篇文章主要介紹了微信JS-SDK自定義分享功能,結(jié)合實(shí)例形式分析了基于JS-SDK接口實(shí)現(xiàn)的分享給朋友及分享到朋友圈等功能的相關(guān)配置文件與數(shù)據(jù)操作技巧,需要的朋友可以參考下2016-11-11javascript sort()對(duì)數(shù)組中的元素進(jìn)行排序詳解
在本篇文章里小編給大家整理是一篇關(guān)于javascript sort()對(duì)數(shù)組中的元素進(jìn)行排序的相關(guān)知識(shí)點(diǎn)內(nèi)容,需要的朋友們學(xué)習(xí)下。2019-10-10一篇文章告訴你如何用事件委托實(shí)現(xiàn)JavaScript留言板功能
這篇文章主要為大家介紹了事件委托實(shí)現(xiàn)JavaScript留言板功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-12-12Layer UI表格列日期格式化及取消自動(dòng)填充日期的實(shí)現(xiàn)方法
這篇文章主要介紹了Layer UI表格列日期格式化及取消自動(dòng)填充日期的實(shí)現(xiàn)方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05Javascript動(dòng)態(tài)創(chuàng)建div的方法
這篇文章主要介紹了Javascript動(dòng)態(tài)創(chuàng)建div的方法,是javascript節(jié)點(diǎn)操作的典型應(yīng)用,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02原生JS檢測(cè)CSS3動(dòng)畫(huà)是否結(jié)束的方法詳解
這篇文章主要介紹了原生JS檢測(cè)CSS3動(dòng)畫(huà)是否結(jié)束的方法,結(jié)合實(shí)例形式分析了javascript事件響應(yīng)及針對(duì)css3屬性檢測(cè)相關(guān)操作技巧,需要的朋友可以參考下2019-01-01