欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

waterfall瀑布流布局+動(dòng)態(tài)渲染的實(shí)現(xiàn)

  發(fā)布時(shí)間:2021-01-19 15:59:08   作者:頑皮的雪狐七七   我要評(píng)論
這篇文章主要介紹了waterfall瀑布流布局+動(dòng)態(tài)渲染的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

瀑布流典型網(wǎng)站

花瓣網(wǎng)、堆糖

瀑布流布局原理

大體思路

首先先是頁面布局 特點(diǎn)是:寬度一樣,長度不一樣

由此可以知道,這種布局要用到 絕對(duì)定位 的思想來做。

上面的五個(gè)正常排列,到了第六個(gè)以后就要找最矮的追加了。

如何獲取最矮的一列呢?

第一個(gè)最好找,其他的每一個(gè)盒子可以獲取它的高度,找最矮的盒子,然后找到最矮盒子的定位。

新追加進(jìn)去的盒子的定位是:

  • left:最矮盒子的索引*(盒子的寬度+左右間距)
  • top: 這個(gè)盒子的高度 + 上下間距

放進(jìn)去之后這一列的高度變化,記錄下來生成新的高度,然后進(jìn)行下一輪高度的比較。以此類推。

waterful 是一個(gè)組件,基于 jquery 的一個(gè)組件。

具體思路

最外邊的左右兩邊是沒有間距的,所以 5 列的情況下有 4 個(gè)間距。所以寬度 width 一定的情況下,間距的寬度 space 是可以計(jì)算出來的:

間距

var space = (wParent - 5 * width) / (col - 1);
// wParent 父盒子的寬度,width是子盒子的寬度,col是列數(shù)

第一排的盒子的定位:

  • top : 0
  • left : 索引*(width + space)

第二排的盒子的定位:

  • top : minHeight + space
  • left : 索引*(width + space)

所以 5 列的高度要用一個(gè)數(shù)組表示,可以找到最矮的元素以及其當(dāng)前的索引。

插件封裝

因?yàn)樵诘谝淮渭虞d和第 n 次加載的時(shí)候,都要進(jìn)行瀑布流布局。所以將瀑布流布局的方法進(jìn)行一個(gè)插件進(jìn)行封裝,可以形成代碼的復(fù)用。 首先了解瀑布流的 html 布局

<!--頁面容器-->
<div class = "container">
      <!--所有item的集合,距離頂部有距離-->
      <div class = "items">
             <!--每一個(gè)小塊,包含了圖片和文字-->
              <div class = "item">
                    <img src = "" />
                    <p>hello</p>
              </div>

              <div class = "item">
                    <img src = "" />
                    <p>hello</p>
              </div>
      </div>
</div>
<div class = "btn">正在加載...</div>

下面就來封裝一個(gè) jquery 的插件

第一步

jquery 中的全局變量轉(zhuǎn)化為局部變量。

防止全局污染,提高性能 形成一個(gè)閉包,閉包里面定義的變量是不會(huì)影響外部變量的。

/*自調(diào)用  形成一個(gè)閉包 */
(function($){
/*如果不加jQuery里面使用的$是全局變量,加了之后使用的就是成員變量*/

})(jQuery);

第二步

jquery.fn.extend(object)

jquery 中的 fn 函數(shù)

提供一個(gè)第三方方法的一個(gè)入口,擴(kuò)展 jquery 元素集(使用 $ 可以獲取到的元素) 來提供新的方法(通常用來制作插件)

/*js/jquery-waterfall.js*/
(function($){
     $.fn.waterfall = function(){
        /*this指向的是當(dāng)前調(diào)用這個(gè)方法的元素集(元素集是jquery獲取元素是一個(gè)偽數(shù)組)*/
         console.log(this);
     }
})(jQuery);

第三步

對(duì)第一排進(jìn)行排列

(function($){
    $.fn.waterfall = function(){
    // this指向的是當(dāng)前調(diào)用這個(gè)方法的元素集
    // 當(dāng)前的瀑布流父容器
        var items = $(this);
        //父容器的寬度
        var wParent = items.width();
        //當(dāng)前的瀑布流子容器
        var child = items.children();
        //獲取子容器的寬度
        var width = child.width();
        //假設(shè)排多少列
        var col = 5;
        //計(jì)算間距(父元素的寬度減所有盒子的寬度/4)
        var space = (wParent - col * width) / (col - 1);

        //記錄每列高度的數(shù)組
        var colHeightArr = [];

        //遍歷每一個(gè)子元素
        $.each(child,function(i,item){
            var $item = $(item);
            var height = $item.height();

            //設(shè)置定位
            //第一排的元素都是靠頂部的,所以索引從0開始,小于5的時(shí)候都是靠頂部的
            if(i < col ){
                $item.css({
                    top: 0,
                    left:i * (width + space)  
                });
               //把高度添加進(jìn)數(shù)組中
                colHeightArr[i] = height;
                //也可以用   colHeightArr.push(height);
            }
            //其他的都要根據(jù)最矮的一列進(jìn)行排列
        });
    }
})(jQuery);

這樣你就看到了效果圖(因?yàn)槟M做了 13 個(gè)盒子,所以剩下的疊在了一起)

這個(gè)時(shí)候打印以下高度數(shù)組:

可以看到前 5 個(gè)的高度都存到數(shù)組中去了。可以判斷出來數(shù)組中最小的是 289 , 289 對(duì)應(yīng)的數(shù)組的索引就是那一列的索引。

第四步

對(duì)其余的排進(jìn)行排列。找最小的追加,然后本列的高度增加。以此類推。 最大的 items 等于最大的高度。這樣才可以把下面的加載移動(dòng)到下邊去。

(function($){
    $.fn.waterfall = function(){
    // this指向的是當(dāng)前調(diào)用這個(gè)方法的元素集
    // 當(dāng)前的瀑布流父容器
        var items = $(this);
        //父容器的寬度
        var wParent = items.width();
        //當(dāng)前的瀑布流子容器
        var child = items.children();
        //獲取子容器的寬度
        var width = child.width();
        //假設(shè)排多少列
        var col = 5;
        //計(jì)算間距
        var space = (wParent - col * width) / (col - 1);

        //記錄每列高度的數(shù)組
        var colHeightArr = [];

        //遍歷每一個(gè)子元素
        $.each(child,function(i,item){
            var $item = $(item);
            var height = $item.height();

            //定位

            //第一排的元素都是靠頂部的

            //索引從0開始,小于5的時(shí)候都是靠頂部的
            if(i < col ){
                $item.css({
                    top: 0,
                    left:i * (width + space)
                });

                //colHeightArr[i] = height;
                colHeightArr.push(height);
   
             //其他的都要根據(jù)最矮的一列進(jìn)行排列
             }else{    
                //找到最矮的那一列進(jìn)行排列
                //索引
                var index = 0;
                //假設(shè)最小的高度是第一個(gè)索引對(duì)應(yīng)的高度
                var minHeight = colHeightArr[index];
                //遍歷數(shù)組,找到最小值和最小值對(duì)應(yīng)的索引
                //k是索引,v是值
                $.each(colHeightArr,function(k,v){
                    if(minHeight > v){
                        index = k;
                        minHeight = v;
                    }
                });

                //定位
                $item.css({
                    top:minHeight + space,
                    left:index * (width + space)
                })

                //當(dāng)前數(shù)組中最小的高度進(jìn)行新的高度的更新
                colHeightArr[index] = minHeight + space + height;
            }
            //console.log(colHeightArr);
        });

        //設(shè)置父容器的高度
        var maxHeight = colHeightArr[0];
        $.each(colHeightArr,function(k,v){
            if(maxHeight < v){
                maxHeight = v;
            }
        });
        //給父容器設(shè)置最高的高度
        items.height(maxHeight);
    }
})(jQuery);

效果圖:

第五步

html 中調(diào)用(上面的效果圖都是已經(jīng)調(diào)用過的)

$(".items").waterfall();

但是如果有圖片的話,這樣調(diào)用在網(wǎng)絡(luò)比較慢的情況下會(huì)出現(xiàn)問題。在圖片沒有加載出來的時(shí)候排列,中間圖片加載完畢會(huì)造成盒子重疊的效果。

解決辦法:

/*頁面上所有的資源都加載完成后進(jìn)行布局,否則獲取不到圖片的尺寸撐不開盒子的高度*/
window.onload = function(){
  $(".items").waterfall();
}

//為什么不用jquery的,因?yàn)檫@個(gè)是在dom元素下載完畢之后進(jìn)行加載這個(gè)方法,需要等所有的資源加載完之后進(jìn)行排列
/*   
$(function(){
	//console.log('dom loaded');
});    
*/

動(dòng)態(tài)渲染

因?yàn)閿?shù)據(jù)很多,所以會(huì)進(jìn)行分批次渲染。

原理圖:

接口文檔:

接口說明: 瀑布流分頁數(shù)據(jù)

接口地址:data.php

請(qǐng)求方式:get

接口參數(shù):page 當(dāng)前是第幾頁

pageSize 當(dāng)前頁要顯示多少條

返回類型:json

返回?cái)?shù)據(jù):

{ page:2,items:[{path:"./images/1.jpg",text:'''},...] }

page 下一頁的頁碼(根據(jù)頁碼獲取下一頁的數(shù)據(jù))

items 返回當(dāng)前頁的數(shù)據(jù)

path 圖片地址

text 文字

此時(shí)我們要準(zhǔn)備好殼子

<div class="container">
    <div class="items">
        <!--TODO 需要渲染數(shù)據(jù)的地方-->
    </div>
    <div class="btn loading">正在加載中...</div>
</div>

需求分析

加載第一頁的時(shí)候

1.加載第一頁的數(shù)據(jù) ajax
2.按鈕需要顯示成加載更多
3.加載完成渲染到頁面當(dāng)中 artTemplate
4.初始化成瀑布流布局 waterfall

加載下一頁的時(shí)候

1.加載數(shù)據(jù)

  • 手動(dòng)加載:點(diǎn)擊按鈕加載下一頁的數(shù)據(jù)
  • 自動(dòng)加載:滾動(dòng)到底部的時(shí)候主動(dòng)加載下一頁

2.按鈕需要顯示 “正在加載中...” 不能點(diǎn)擊 防止重復(fù)提交
3.加載完成渲染到頁面當(dāng)中
4.初始化成瀑布流布局
5.按鈕需要顯示成加載更多
沒有更多數(shù)據(jù)把按鈕禁用 顯示 “沒有更多數(shù)據(jù)了”

渲染第一頁數(shù)據(jù)

發(fā)送請(qǐng)求

既然加載頁面的時(shí)候都會(huì)用到加載數(shù)據(jù)、渲染頁面、初始化瀑布流,就把這三個(gè)動(dòng)能封裝到一個(gè)函數(shù)中去,先實(shí)現(xiàn)第一個(gè)功能:

$(function(){
        //實(shí)現(xiàn)動(dòng)態(tài)的瀑布流渲染
      
        //渲染
        var render = function(){
            // 加載數(shù)據(jù)  渲染頁面  瀑布流布局
            $.ajax({
                type:'get',
                url:'data.php',
                data:{
                    //第一頁
                    page:1,
                    //每頁10條
                    pageSize:10
                },
                dataType:'json',
                success:function(data){
                    console.log(data);
                }
            });
        }

        render();
    });

拿到的數(shù)據(jù)如圖:

渲染頁面

準(zhǔn)備模板

<script type="text/template" id="template">
    <% for(var i=0 ; i<items.length ; i++){ %>
        <div class="item">
            <img src="<%=items[i].path%>" alt="">
            <p><%=items[i].text%></p>
        </div>
    <% } %>
</script>

<script>
  $(function(){
    //獲取需要操作的dom
    var $items = $(".items");
    var $btn = $(".btn");
    //渲染
    var render = function(){
        // 加載數(shù)據(jù)  渲染頁面  瀑布流布局
        $.ajax({
            type:'get',
            url:'data.php',
            data:{
                page:1,
                pageSize:10
            },
            dataType:'json',
            success:function(data){
                console.log(data);
                $items.append(template('template',data));
                //瀑布流布局
                $items.waterfall();
                //更改按鈕
                $btn.removeClass('loading').html('加載更多');
            }
        });
    }
    
    render();
  });
</script>

第二頁面的渲染(手動(dòng)加載)

第二頁需要改變的東西:

  • 添加按鈕的點(diǎn)擊事件,點(diǎn)擊按鈕之后就進(jìn)行渲染。
  • 點(diǎn)擊按鈕加載的時(shí)候,要給按鈕加鎖,因?yàn)椴患拥脑挄?huì)發(fā)送多個(gè)ajax請(qǐng)求,判斷按鈕是不是loading狀態(tài),如果是的話就不渲染數(shù)據(jù)。
  • render函數(shù)中,在進(jìn)行按鈕狀態(tài)改變的時(shí)候,用自定義屬性記錄下來下一頁的要獲取的頁數(shù)。利用data(),里面?zhèn)饕粋€(gè)page,把data.page放進(jìn)去。所以在拿數(shù)據(jù)的時(shí)候,要從按鈕的data中獲取page的值。第一次是空的,所以就設(shè)定一個(gè)默認(rèn)值為1
  • render函數(shù)中在數(shù)據(jù)成功加載之前,按鈕還是loading狀態(tài),所以加一個(gè)beforeSend的函數(shù),里面是loading狀態(tài)。
  • render函數(shù)中在渲染的時(shí)候判斷一下是不是沒有數(shù)據(jù)了,根據(jù)返回的數(shù)組中的長度是不是為零來判斷,如果是零的話就顯示沒有更多數(shù)據(jù)了。
 $(function(){
    //獲取需要操作的dom
    var $items = $(".items");
    var $btn = $(".btn");

    //渲染
    var render = function(){
        // 加載數(shù)據(jù)  渲染頁面  瀑布流布局
        $.ajax({
            type:'get',
            url:'data.php',
            data:{
                //取下一頁的頁碼,沒有的話就默認(rèn)是1
                page:$btn.data("page")||1,
                //每頁10條
                pageSize:10
            },
            beforeSend:function(){
                $btn.addClass("loading").html('正在加載中...');
            },
            dataType:'json',
            success:function(data){
                console.log(data);
                //準(zhǔn)備模板
                //因?yàn)槭亲芳铀圆荒苡胔tml,要用append
                        //直接用data的原因是因?yàn)閐ata本來就是一個(gè)對(duì)象,里面有很多的屬性,而不是一個(gè)數(shù)組,數(shù)組的話不能這樣,因?yàn)閿?shù)據(jù)只有l(wèi)ength一個(gè)屬性
                $items.append(template('template',data));
                //瀑布流布局
                $items.waterfall();

                if(data.items.length){
                    //更改按鈕
                    //data是一個(gè)自定義屬性,把數(shù)據(jù)中傳輸出來的page保存在自定義屬性當(dāng)中,
                    $btn.data("page",data.page).removeClass('loading').html('加載更多');
                }else{
                    //沒有更多數(shù)據(jù)
                    //判斷什么時(shí)候就沒有數(shù)據(jù)了,打開最后的一個(gè)對(duì)象,里面items的數(shù)組的長度為零
                    $btn.addClass("loading").html("沒有更多數(shù)據(jù)了");
                }
            }
        });
    }

    //按鈕加載
    $btn.on('click',function(){
        //避免發(fā)送多個(gè)ajax請(qǐng)求,就進(jìn)行判斷,如果是loading狀態(tài),就退出,
        if($btn.hasClass("loading")){
            return false;
        }
        render();
    })

    render();
});

第二頁面的渲染(滾動(dòng)加載)

說到滾動(dòng)渲染,就是要我們渲染過的頁面到瀏覽器底部的一定距離就要進(jìn)行下一次的請(qǐng)求了,這就要進(jìn)行一個(gè)判斷了。

原理圖:

當(dāng) bottom < 200px 的時(shí)候進(jìn)行 ajax 請(qǐng)求。

其中 bottom 要怎么計(jì)算?

bottom = items的高度 + items距離頂部的距離 - 向上卷曲的高度 - 整個(gè)瀏覽器的高度

 $(function(){
    //實(shí)現(xiàn)動(dòng)態(tài)的瀑布流渲染

    //獲取需要操作的dom
    var $items = $(".items");
    var $btn = $(".btn");

    //渲染
    var render = function(){
        // 加載數(shù)據(jù)  渲染頁面  瀑布流布局
        $.ajax({
            type:'get',
            url:'data.php',
            data:{
                page:$btn.data("page")||1,   
                pageSize:10
            },
            beforeSend:function(){
                $btn.addClass("loading").html('正在加載中...');
            },
            dataType:'json',
            success:function(data){
                console.log(data);
                $items.append(template('template',data));
                //瀑布流布局
                $items.waterfall();

                //判斷數(shù)組中有沒有數(shù)據(jù)
                if(data.items.length){
                 $btn.data("page",data.page).removeClass("loading").html('加載更多');
                }else{
                    $btn.addClass("loading").html("沒有更多數(shù)據(jù)了");
                }
            }
        });
    }

    //滾動(dòng)加載
    $(window).on('scroll',function(){
        //文檔距離底部的距離小于200px 去加載
        //并且加載完成才能繼續(xù)加載

        //items的高度
        var itemsHeight = $items.height();
        //items距離頂部的偏移量
        var itemsTop = $items.offset().top;
        //整個(gè)頁面距離頂部的卷曲出去的距離
        var scrollTop = $(document).scrollTop();
        // 瀏覽器的高度
        var winHeight = $(window).height();
        //  瀏覽器底部距離items底部的距離
        var bottom = itemsHeight + itemsTop - scrollTop -winHeight;
        //  判斷按鈕是不是loading狀態(tài)
        var loading = $btn.hasClass("loading");

        //如果按鈕小于200 且 不是loading狀態(tài)就開始加載
        if(bottom < 200 && !loading){
            render();
        }
    })

    render();
});

需要特別注意的問題

之前我們?cè)陟o態(tài)加載頁面的時(shí)候使用的是 window.onload ,是為了讓頁面上的資源全部加載完成之后再進(jìn)行頁面的渲染。否則就會(huì)產(chǎn)生頁面重疊的現(xiàn)象。

在動(dòng)態(tài)加載頁面的時(shí)候,我們先拿到后臺(tái)的數(shù)據(jù),然后轉(zhuǎn)化成 html 追加到頁面上之后,才開始加載 img 圖片。這里也遇到了之前的問題。

之所以后面沒有用 window.onload 那樣的做,是因?yàn)樵驹O(shè)置的圖片已經(jīng)設(shè)定可寬和高。 img 有的設(shè)定了 250px ,有的設(shè)定了 450px 。 但是這樣做不合理,因?yàn)橛械膱D片會(huì)變形。

下面提供解決問題的方法:

  1. 等所有的圖片加載完成進(jìn)行頁面渲染,但是這樣時(shí)間會(huì)比較長,不合理。
  2. 參考花瓣

花瓣在加載圖片的時(shí)候也進(jìn)行了寬高的設(shè)定,但是這個(gè)大小要根據(jù)原圖片的尺寸進(jìn)行大小的縮放。

原來的尺寸是 608 ,現(xiàn)在的寬度是 200 ,那么現(xiàn)在的高度就進(jìn)行一個(gè)換算

現(xiàn)在的高度 = 200 / 806 * 782

width 是現(xiàn)在的寬度

// 模板引擎中寫
<img height = "<%=items[i].width * items[i].height / width%>" src = "<%=items[i].path%>" />
/*  
同樣在ajax的success中
$items.append(
    template('template',{
        data:data,
        width:width
    })
);
這樣width變量就可以使用了。
*/

這樣瀑布流就完成了.

到此這篇關(guān)于waterfall瀑布流布局+動(dòng)態(tài)渲染的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)waterfall瀑布流布局內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論