原生JS - 瀑布流布局@郝晨光

前言

瀑布流布局在我們現(xiàn)在的前端頁面中經(jīng)常會(huì)用的到聚请,它可以有效的降低頁面的復(fù)雜度怒竿,節(jié)省很多的空間砍鸠,對(duì)于整個(gè)頁面不需要太多的操作,只需要下拉就可以瀏覽用戶需要看到的數(shù)據(jù)耕驰;并且爷辱,在當(dāng)前這個(gè)APP至上的時(shí)代,瀑布流可以提供很好的用戶體驗(yàn)朦肘,通過結(jié)合下拉刷新饭弓,上拉加載進(jìn)行數(shù)據(jù)的懶加載等操作,對(duì)于用戶的體驗(yàn)感來說是接近于滿分的媒抠!
本文參考鏈接:淺談瀑布流 - 作者:evenyao弟断,感謝作者提供的思路以及圖片。

瀑布流布局

正文

瀑布流的特點(diǎn)

其實(shí)瀑布流的特點(diǎn)就是參差不齊的排列方式领舰,以及流式布局的擴(kuò)展性夫嗓,可以通過界面展示給用戶多條數(shù)據(jù),并且讓用戶可以有向下瀏覽的沖動(dòng)冲秽。

瀑布流的原理

通過將元素定位舍咖,并且通過javascript動(dòng)態(tài)的計(jì)算每一項(xiàng)元素的所處位置,給元素動(dòng)態(tài)的設(shè)置left和top值锉桑,讓它待在自己應(yīng)該在的位置排霉。
即多行等寬元素排列,后面的元素依次添加到其后民轴,等寬不等高攻柠,依次按照規(guī)則放入指定位置球订。

瀑布流的位置分析:淺談瀑布流 - 作者:evenyao

當(dāng)?shù)谝慌排艥M足夠多的等寬圖片時(shí)(如下圖情況),自然而然的考慮到之后放置的圖片會(huì)往下面排放瑰钮。


淺談瀑布流 - 作者:evenyao

那么第六張圖片冒滩,放置在什么位置呢?按我們正常的邏輯來看浪谴,應(yīng)該是下圖的位置么开睡?


淺談瀑布流 - 作者:evenyao

但是,在瀑布流中苟耻,我們的第六張圖的位置應(yīng)該是第一行中的高度最低的那一張圖片的下方篇恒。
淺談瀑布流 - 作者:evenyao

為什么呢?
因?yàn)榉胖盟靶渍龋@一列的高度為所有列中最小胁艰,所以會(huì)放置在這個(gè)地方。
所以我們知道了智蝠,如果再繼續(xù)放置下去腾么,第七張圖片應(yīng)該是這個(gè)位置,對(duì)嗎寻咒?


淺談瀑布流 - 作者:evenyao

通過瀑布流算法實(shí)驗(yàn)得出位置正確哮翘。看懂這個(gè)圖示應(yīng)該就能理解了瀑布流的原理算法毛秘。
淺談瀑布流 - 作者:evenyao

代碼實(shí)現(xiàn)

對(duì)于我自己實(shí)現(xiàn)的這個(gè)瀑布流demo來說饭寺,相較于別人的,有幾點(diǎn)差別需要提一下:

  1. 在間距計(jì)算方面叫挟,別人都是使用固定間距艰匙,這樣會(huì)造成一個(gè)問題是頁面右邊距過大或過小,影響美觀抹恳;我使用的是固定最小間距员凝,通過最小間距計(jì)算出實(shí)際間距。保證每個(gè)元素之間的間距都是相等的奋献。
  2. 在實(shí)現(xiàn)的時(shí)候健霹,考慮到了滾動(dòng)條的寬度問題,使用自定義的函數(shù)獲取到了滾動(dòng)條的寬度并在實(shí)際計(jì)算中減去滾動(dòng)條寬度瓶蚂。所以始終左右間距保持一致糖埋。
// 定義瀑布流算法函數(shù)
function fall() {
    const minGap = 20; // 最小間距,讓每一列的最小空隙可以自定義窃这,避免太過擁擠的情況發(fā)生瞳别。但是,會(huì)通過計(jì)算得到真實(shí)的間距。
    const itemWidth = 100; // 每一項(xiàng)的寬度祟敛,即當(dāng)前每一個(gè)圖片容器的寬度疤坝。保證每一列都是等寬不等高的。
    const scrollBarWidth = getScrollbarWidth();
    const pageWidth = window.innerWidth - scrollBarWidth; // 獲取當(dāng)前頁面的寬度 = window.innerWidth - 滾動(dòng)條的寬度
    const column = Math.floor(pageWidth / (itemWidth + minGap)); // 實(shí)際列數(shù)
    const gap = (pageWidth - itemWidth * column) / column / ((column + 1) / column); // 計(jì)算真實(shí)間距
    const items = document.querySelectorAll('li'); // 獲取所有的外層元素
    const heightArr = []; // 定義一個(gè)空數(shù)組馆铁,保存最低高度跑揉。
    for (let i = 0; i < items.length; i++) {
        // 遍歷所有的外層容器
        const height = items[i].offsetHeight;
        // 如果當(dāng)前處在第一列
        if (i < column) {
            // 直接設(shè)置元素距離上部的位置和距離左邊的距離。
            items[i].style.cssText = `top: ${gap}px;left: ${(itemWidth + gap) * i + gap}px`;
            // 保存當(dāng)前元素的高度叼架。
            heightArr.push(height);
        } else {
            // 不是第一列的話畔裕,就進(jìn)行比對(duì)。
            let minHeight = heightArr[0]; // 先保存第一項(xiàng)的高度
            let minIndex = 0; // 保存第一項(xiàng)的索引值
            for (let j = 0; j < heightArr.length; j++) {
                // 通過循環(huán)遍歷比對(duì)乖订,拿到最小值和最小值的索引。
                if (minHeight > heightArr[j]) {
                    minHeight = heightArr[j];
                    minIndex = j;
                }
            }
            // 通過最小值為當(dāng)前元素設(shè)置top值具练,通過索引為當(dāng)前元素設(shè)置left值乍构。
            items[i].style.cssText = `top: ${minHeight + gap *2}px; left: ${(itemWidth + gap) * minIndex + gap}px`;
            // 并修改當(dāng)前索引的高度為當(dāng)前元素的高度
            heightArr[minIndex] = minHeight + gap + height;
        }
    }
}
// 頁面加載完成調(diào)用一次。
window.onload = fall;
// 頁面尺寸發(fā)生改變?cè)俅握{(diào)用扛点。
window.onresize = fall;

// 獲取滾動(dòng)條的寬度
function getScrollbarWidth() {
    const oDiv = document.createElement('div');//創(chuàng)建一個(gè)div
    // 給div設(shè)置樣式哥遮。隨便定義寬高,只要能獲取到滾動(dòng)條就可以
    oDiv.style.cssText = `width: 50px;height: 50px;overflowY: scroll;` 
    document.body.appendChild(oDiv);//把div添加到body中
    const scrollbarWidth = oDiv.offsetWidth - oDiv.clientWidth;// 使最大寬度和可視寬度相減陵究,獲得到滾動(dòng)條寬度眠饮。
    oDiv.remove();//移除創(chuàng)建的div
    return scrollbarWidth;//返回滾動(dòng)條寬度
}

實(shí)現(xiàn)效果:

瀑布流布局實(shí)現(xiàn)效果



如果本文對(duì)您有幫助,可以看看本人的其他文章:
原生JS - 圖片懶加載@郝晨光
Koa - Node.js框架學(xué)習(xí)@郝晨光
前端常見面試題(十二)@郝晨光

結(jié)言
感謝您的查閱铜邮,本文由郝晨光整理并總結(jié)仪召,代碼冗余或者有錯(cuò)誤的地方望不吝賜教;菜鳥一枚松蒜,請(qǐng)多關(guān)照
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扔茅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子秸苗,更是在濱河造成了極大的恐慌召娜,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惊楼,死亡現(xiàn)場離奇詭異玖瘸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)檀咙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門雅倒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人攀芯,你說我怎么就攤上這事屯断。” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵殖演,是天一觀的道長氧秘。 經(jīng)常有香客問我,道長趴久,這世上最難降的妖魔是什么丸相? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮彼棍,結(jié)果婚禮上灭忠,老公的妹妹穿的比我還像新娘。我一直安慰自己座硕,他們只是感情好弛作,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著华匾,像睡著了一般映琳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜘拉,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天萨西,我揣著相機(jī)與錄音,去河邊找鬼旭旭。 笑死谎脯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的持寄。 我是一名探鬼主播源梭,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼际看!你這毒婦竟也來了咸产?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤仲闽,失蹤者是張志新(化名)和其女友劉穎脑溢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赖欣,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屑彻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了顶吮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片社牲。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖悴了,靈堂內(nèi)的尸體忽然破棺而出搏恤,到底是詐尸還是另有隱情违寿,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布熟空,位于F島的核電站藤巢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏息罗。R本人自食惡果不足惜掂咒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迈喉。 院中可真熱鬧绍刮,春花似錦、人聲如沸挨摸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽油坝。三九已至嫉戚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澈圈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工帆啃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞬女,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓努潘,卻偏偏與公主長得像诽偷,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子疯坤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案报慕? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,728評(píng)論 1 92
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 簡述圖片懶加載的實(shí)現(xiàn)原理 原理:先將img標(biāo)簽中的src鏈接設(shè)為同一張圖片(空白圖片),將其真正的圖片地址存儲(chǔ)再i...
    饑人谷_阿銀閱讀 380評(píng)論 0 0
  • 前言 在現(xiàn)在以用戶體驗(yàn)至上的前端時(shí)代压怠,為了提升頁面加載速度眠冈,為了提升用戶體驗(yàn),我們經(jīng)常會(huì)用到圖片懶加載這個(gè)功能菌瘫。所...
    郝晨光閱讀 1,232評(píng)論 2 21
  • 忽然想在今天寫點(diǎn)什么蜗顽,不為什么,只想紀(jì)念以感謝我的老爸老媽雨让! 孩子的生日是媽媽的母難日雇盖,以前其實(shí)沒多大體會(huì),但是今...
    Kevin5304閱讀 777評(píng)論 0 3