阿里面試—如何用 JS 實現(xiàn)瀑布流布局

手把手帶你攻克 瀑布流布局
前言
瀑布流布局,是現(xiàn)在比較流行的一種頁面布局方式,即多行等寬元素排列,等寬不等高,后面的元素依次添加到前一行最矮的元素下方。

它可以有效的降低頁面的復雜度,節(jié)省很多的空間;并且,瀑布流的參差不齊的排列方式,可以通過界面展示給用戶多條數(shù)據(jù),并且讓用戶可以有向下瀏覽的沖動,提供了很好的用戶體驗!例如淘寶的頁面就采用了這種布局方式,給大家看看淘寶的瀑布流布局的效果圖(手機端)以及我們要實現(xiàn)的效果圖(PC端)吧~


思路準備
通過了解瀑布流布局的方式,我們來梳理一下實現(xiàn)它的步驟,方便我們代碼的編寫。

1、首先我們需要準備很多張圖片(我這準備的是40張),還有vscode開發(fā)工具。

2、編寫前端代碼,給圖片添加樣式讓圖片等寬并同行顯示。

3、編寫js代碼,要知道第一行圖片數(shù)量,下一張圖片的序號以及前一行最矮的元素的序號,還有擺放的位置。

正文
一、前端代碼編寫
1、首先我們定義一個container容器來裝所有圖片,在這個容器中用box容器裝box-img容器再裝入每張圖片,這樣方便之后樣式的編寫。

2、使圖片同行顯示--給box容器使用float:left;屬性。

3、讓圖片等寬顯示--給box-img容器設置**width:150px;,img標簽設置width:100%;繼承父容器box-img高度的100%**。

4、為了使效果更好看,我們給裝圖片的容器設置內(nèi)邊距,邊框和陰影的效果。

前端完整代碼附上:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>waterFall</title>
    <script src="./index.js"></script>
</head>
<style>
    *{
        margin: 0;
        padding: 0;
    }
    .container {
        overflow: hidden;
        position: relative;
    }
    .box{
        float: left;
        padding: 5px;
    }
    .box-img{
        width: 150px;
        padding: 5px;
        border: 1px solid #484848;
        box-shadow: 0 0 5px #484848;
    }
    .box-img img{
        width: 100%;
    }
</style>
<body>
    <div id="container">
        <div class="box">
            <div class="box-img">
                <img src="./img/1.jpg" alt="">
           </div>
        </div>
        /*.......后面接39個box,此處省略*/
    </div>
    
</body>
</html>
復制代碼
二、js代碼編寫
1、首先用window.onload=function(){}來實現(xiàn)頁面加載完畢后立即執(zhí)行的功能
在這個函數(shù)中,我們調用imgLocation('container','box')函數(shù)來呈現(xiàn)最終效果,傳入的實參是父容器'container'以及裝圖片的子容器'box'。

window.onload=function() {
    imgLocation('container','box')
}
復制代碼
2、實現(xiàn)imgLocation()函數(shù)功能
1)首先我們得獲取所有要擺放的圖片,并將其存入一個數(shù)組中
利用document.getElementById(parent)得到父容器;

調用getChildElement(cparent,content)方法,在這個方法中,先獲取父容器所有標簽,對所有標簽遍歷并用if條件語句得到類名為box的容器(裝圖片的容器),將其存入我們自己構建的一個數(shù)組中,返回值為這個數(shù)組,方便之后通過遍歷來操作圖片擺放的位置。

function imgLocation(parent,content){
    var cparent=document.getElementById(parent)
    //cparent下的所有的第一層的子容器 box
    var ccontent=getChildElement(cparent,content)//數(shù)組,40個div
}

//取到父容器中的某一層子容器
function getChildElement(parent,content){
    var contentArr=[]
    var allContent=parent.getElementsByTagName('*')//通過標簽來選中得到一個數(shù)組
    //遍歷allContent把其中類名為content的容器都存到contentArr數(shù)組中
    for(var i=0;i<allContent.length;i++){
        if(allContent[i].className==content){    //當前這個容器的類名是否為content
            contentArr.push(allContent[i])
        }
    }
    return contentArr;

}
復制代碼
2)得到這個數(shù)組后,找出從誰開始是需要被擺放位置的
我們采用以下方法:

首先獲取視窗的寬度和每張圖片的寬度,將兩者相除并向下取整可得到第一行可以放置圖片的數(shù)量,自然也就知道了我們需要操作的那張圖片的序號。

    //從誰開始是需要被擺放位置的
    var winWidth=document.documentElement.clientWidth;//視窗寬度
    var imgWidth=ccontent[0].offsetWidth;//圖片寬度

    var num=Math.floor(winWidth/imgWidth)//第一行能放幾張圖
復制代碼
3)得到需要被擺放位置的圖片序號后,確定其擺放位置
我們自己定義一個存儲高度的數(shù)組,對前一行元素的高度進行遍歷并存入數(shù)組,當遍歷到需要被擺放位置的圖片時,用Math.min()方法獲取前一行高度最矮的元素高度,并用indexOf()方法獲取到其下標。

再對我們所操作的這個圖片容器的樣式調整:
position:absolute;絕對定位, top值設置為前一行高度最矮的圖片高度minHeight,left值設置為單張圖片寬度乘這張圖片的下標minIndex。

最后,不要忘啦,擺放好圖片后,還要更新擺放的那一列的高度喲~

    //操作num+1張圖
    var BoxHeightArr=[]
    for(var i=0;i<ccontent.length;i++){
        //前num張只要計算高度
        if(i<num){
            BoxHeightArr[i]=ccontent[i].offsetHeight
        }
        else{
            //我們要操作的box  :ccontent[i]
            var minHeight=Math.min.apply(null,BoxHeightArr)//apply:把最小值這個方法借給它用
            var minIndex=BoxHeightArr.indexOf(minHeight)//返回數(shù)組下標
            ccontent[i].style.position='absolute'//style設置樣式
            ccontent[i].style.top=minHeight+'px'
            ccontent[i].style.left=imgWidth*minIndex+'px'

            //更新最矮的那一列的高度
            BoxHeightArr[minIndex]+=ccontent[i].offsetHeight
        }
    }
復制代碼
最終整合一下就可以實現(xiàn)瀑布流的布局效果啦!

最后
以上就是瀑布流布局的實現(xiàn)過程,看完本文如果覺得有用,記得點個贊支持,收藏起來說不定哪天就用上啦~
文章可能有一些錯誤,歡迎評論指出,也歡迎一起討論。

關于本文

作者:zt_ever

https://juejin.cn/post/7216200378341589052






作者:zt_ever


歡迎關注微信公眾號 :前端Q