1. 程式人生 > 實用技巧 >WEB前端第四十二課——瀑布流

WEB前端第四十二課——瀑布流

1.瀑布流

  又稱為瀑布流式佈局,是一種比較流行的網站頁面佈局。

  視覺表現為參差不齊的多欄佈局,隨著頁面滾動條向下滾動,不斷載入資料塊並附加至當前尾部。

  優點:

    ①有效降低頁面複雜度,節省了空間,不再需要臃腫複雜的頁碼導航連線或按鈕;

    ②對觸屏裝置來說,互動方式更符合直覺,尤其在移動應用的互動環境中,降低了操作精準度要求;

    ③更高的參與度,以上兩點所帶來的的互動便捷性,可以使使用者將注意力更多的集中在內容而不是操作上。

  說明事項:

    ①通常瀑布流對於元素的高度並沒有限制,但是為了便於計算,很多時候瀑布流元素的寬度要求相同;

    ②瀑布流的頁面元素,第一行元素正常排列;

    ③從第二行元素開始,每一個元素都依次排在當前高度最矮的元素列下面;

    ④ 瀑布流可以做到無限滾動,永遠載入不完。

2.瀑布流案例

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>無限瀑布流</title>
    <style>
        *{margin: 0;padding: 0;}
        .containerBox{
            margin: 0 auto;     /*div容器不設定寬高,由內容撐開,居中顯示*/
            padding: 0;
            position: relative;     /*所有瀑布流內容相對div容器進行定位*/
        }
        .picDiv{
            float: left;
            cursor: pointer;
        }
        .picDiv:hover img{
            box-shadow: 0 0 10px orangered;
            transform:translate(1px,-6px);
        }
        img{
            margin: 10px;
            padding: 10px;
            border: 1px solid hotpink;
            border-radius: 5px;
            box-shadow: 0 0 5px darkorange;
            transition: all .3s;
        }
        /*也可以通過“picDiv”設定邊框格式,但通過”img“設定的好處在於
                “picDiv”的寬度就是包含了所有佔用空間,這樣便於佈局尺寸計算!*/
    </style>
</head>
<body>
    <div class="containerBox"></div>
<script>
// <!--模擬後臺獲取資料(JSON字串)-->
    var dataStr='{"picName":["vogue01.jpg","vogue02.jpg","vogue03.jpg","vogue04.jpg","vogue05.jpg","vogue06.jpg","vogue07.jpg","vogue08.jpg","vogue09.jpg","vogue10.jpg","vogue11.jpg","vogue12.jpg","vogue13.jpg","vogue14.jpg","vogue15.jpg","vogue16.jpg","vogue17.jpg","vogue18.jpg","vogue19.jpg","vogue20.jpg","vogue21.jpg","vogue22.jpg","vogue23.jpg","vogue24.jpg","vogue25.jpg","vogue26.jpg","vogue27.jpg","vogue28.jpg","vogue29.jpg"]}';
//  將JSON字串轉換成js物件
    var jsPicObj=JSON.parse(dataStr);
    var containerBox=document.querySelector(".containerBox");

//  ① 獲取div元素,使用“for”迴圈將圖片內容新增到容器中,
//  ② 將“for”迴圈封裝成函式
    function catchPics() {
        for (var i=0;i<jsPicObj.picName.length;i++){
            var waterFallPic=jsPicObj.picName[i];
            var picDiv=document.createElement('div');
            // 使用“innerHTML”屬性將圖片新增至各個div中,
            // innerHTML的value使用<img/>標籤,通過<img/>的“src”屬性引用圖片(需拼接圖片地址)
            picDiv.innerHTML='<img src="Images/WaterFall/'+waterFallPic+'"/>';
            containerBox.appendChild(picDiv);
            // picDiv.setAttribute("float","left");     //使用“setAttribute”方法無效??
            // picDiv.style.cssFloat='left';
            picDiv.className='picDiv';
        }
    }

//  構建瀑布流佈局
//  ③ 將整個構建過程封裝成函式
    function creatWaterFall() {
//   在“containerBox”沒有設定“width”屬性值的情況下,預設佔據整個頁面寬度,
//   此時通過margin屬性設定div居中沒有效果,通過“picDiv”的寬度設定“containerBox”的寬度。
//  ① 獲取圖片元素,通過圖片元素的寬度屬性計算“containerBox”的寬度,有了width屬性值margin居中設定才有效果。
        var picDivCol=document.querySelectorAll('.picDiv');
        var singleWidth=picDivCol[0].clientWidth;
        var bodyWidth=document.documentElement.clientWidth||document.body.clientWidth;  //相容考慮
        var rowPicNum=Math.floor(bodyWidth/singleWidth);
        containerBox.style.width=singleWidth*rowPicNum+'px';
//  ② 使用 for迴圈從第二行開始將圖片依次逐一放到當前累計高度最小的一列後面
        var columnHeightArr=[];
        for (var j=0;j<picDivCol.length;j++){
            if (j<rowPicNum){
            //  第一行圖片按正常流排列,將每一列的高度以陣列的形式儲存
                columnHeightArr.push(picDivCol[j].clientHeight);
            }else {
            //  從第二行開始每個圖片設定絕對定位,通過“style.top/left”屬性將其放置在指定位置
                picDivCol[j].style.position='absolute';
            //  Math.min()方法內部需要的是數字型別,通過apply()方法呼叫Math。
                var shortHeight=Math.min.apply(null,columnHeightArr);
                var shortHeightIndex=columnHeightArr.indexOf(shortHeight);
            //  以累計高度最小的列元素的左定位作為第“j”個圖片的left位移,其當前累計高度作為第“j”個圖片的top位移。
                picDivCol[j].style.left=picDivCol[shortHeightIndex].offsetLeft+'px';
                picDivCol[j].style.top=columnHeightArr[shortHeightIndex]+'px';
            //  每放置一個圖片後,需要將該圖片的高度累加到當前列的累計高度上
                columnHeightArr[shortHeightIndex]=picDivCol[j].clientHeight+shortHeight;
            }
        }
    }
    catchPics();
//  由於構建瀑布流過程中需要用到圖片的資料資訊,如果執行函式時圖片尚未載入完成會導致異常,
//  而 onload事件是圖片內容載入完成後才會觸發
    window.onload=function () {
            creatWaterFall();
        }

//  設定無限瀑布流
//  基本思路:當圖片集合中的最後一張圖片即將出現在可視區域時,進行瀑布流重複載入
    window.onscroll=function () {
        var picDivCol=document.querySelectorAll('.picDiv');     //能不能與構建函式中的宣告合併為一個??
        var maxIndex=picDivCol.length-1;
        var checkDist=picDivCol[maxIndex].offsetTop;
        var scrollDist=document.documentElement.scrollTop||document.body.scrollTop;
        var bodyHeight=document.documentElement.clientHeight;
        if (checkDist<=scrollDist+bodyHeight){
            catchPics();
            creatWaterFall();       //首次載入已經獲取圖片資料,不再需要通過 onload事件
        }
    }
/*  無限瀑布流設定的另外一種書寫方式:
    function trigger() {
        var picDivCol=document.querySelectorAll('.picDiv');
        var maxIndex=picDivCol.length-1;
        var checkDist=picDivCol[maxIndex].offsetTop;
        var scrollDist=document.documentElement.scrollTop||document.body.scrollTop;
        var bodyHeight=document.documentElement.clientHeight;
        if (checkDist<=scrollDist+bodyHeight){
            return true;
        }
    }
    window.onscroll=function () {
        if (trigger()){
            catchPics();
            creatWaterFall();
        }
    }*/
</script>
</body>
</html>

3.知識碎片

  ①clientWidth、clientHeight,分別表示元素節點可見部分的寬度和高度,以clientWidth為例進行說明,

    element.clientWidth的值包括padding,但不包括滾動條、border和 margin,

    document.clientWidth與 window.innerWidth減去滾動條寬度的值相等。

  ②offsetWidth、offsetHeight,分別表示元素節點的水平寬度和高度,

    element.offsetWidth的值包括padding、滾動條、border。

  ③Math.min.apply()方法,由於Math相關方法的引數都要求是數值型資料,

    而apply()方不僅可以改變函式的用著,並且要求的引數是陣列型別。

  ④window.onload,對依賴圖片的相關計算或函式,通過onload事件進行載入,

    避免執行時依賴的圖片資源還沒有載入完成導致函式執行失敗。