瀑布流效果

html結(jié)構(gòu)

(Emmet)

(div.box>div.pic>img[src="images/$.jpg"])*23

? ? ? ? ? ?

![](images/1.jpg)

? ? ? ? ? ?

![](images/2.jpg)

? ? ? ? ? ?

![](images/3.jpg)

? ? ? ? ? ?

![](images/4.jpg)

css結(jié)構(gòu)

*{

? ? margin:0;

? ? padding:0;

}

#main{

? ? position: relative;

}

.box{

? ? padding:10px 0 0 15px;

? ? /*display: inline-block;一行顯示*/

? ? float: left;

}

.pic{

? ? padding: 10px;

? ? border:1px solid #ccc;

? ? border-radius: 5px;

? ? box-shadow: 0 0 5px #ccc;

}

.pic img{

? ? /*瀑布流特點(diǎn)*/

? ? width: 165px;

? ? height: auto;

}

一丹弱、JavaScript原生方法實(shí)現(xiàn)瀑布流布局

整個功能封裝在waterfall()函數(shù)中麻捻。

圖片定位

js文件是在head中引入罪既,所以執(zhí)行的腳本需要放在window.onload事件中闰歪。

因?yàn)槲覀冞M(jìn)行操作的是main下的box元素,首先要先進(jìn)行獲取元素轰驳。

然鵝拉岁,js中沒有提供專門獲取Class名的元素的方法驶乾。又為了方面后面的函數(shù)的調(diào)用,我們將獲取父元素main下的所有class為box的子元素的這個功能進(jìn)行封裝getByClass()金刁。

window.onload = function () {

? ? ? waterfall('main','box');

}

function waterfall(parent,box){

? ? //把父元素main下所有class名為box的子元素都取出來

? ? var oParent = document.getElementById(parent);

? ? getByClass(oParent,box);

}

getByClass()實(shí)現(xiàn)的思路:若要獲取父元素下所有class為特定名的子元素帅涂,首先要把父元素下所有子元素全部都取出來,然后進(jìn)行遍歷尤蛮,判斷每個子元素上的className是否和你傳入的class名相等媳友;如果相等,這個子元素就是我們要找的产捞,然后把這些我們要找的子元素存儲起來boxArr醇锚。

這里,通過Class取到的所有元素,最后的結(jié)果是數(shù)組類型(不止一個)焊唬。

獲取到的元素要存儲起來恋昼,boxArr.push()向數(shù)組的末尾添加元素。

//根據(jù)class獲取元素

function getByClass(parent,clsName){

? ? var boxArr = new Array(),//用來存儲獲取到的所有class為box的元素

? ? ? ? oElements = parent.getElementsByTagName('*');//取出父元素下的所有子元素

? ? for (var i = 0; i < oElements.length; i++) {

? ? ? ? if(oElements[i].className == clsName){

? ? ? ? ? ? boxArr.push(oElements[i]);

? ? ? ? }

? ? }

? ? return boxArr;

}

getByClass()函數(shù)最后返回的是一個數(shù)組赶促,var oBoxs = getByClass(oParent,box);聲明一個變量oBoxs來接收獲取到的所有元素液肌。console.log(oBoxs.length);// 23 說明已經(jīng)全部取出

這樣就把ID為main的父元素下所有class為box的子元素都取出來了。

問題:

oElements[i].className == className? 鸥滨,用這種方法判斷嗦哆,欠妥當(dāng)。

因?yàn)楝F(xiàn)實(shí)項(xiàng)目中婿滓,className 不止一個吝秕,這樣就永遠(yuǎn)沒法相等,應(yīng)該這樣判斷

oElements[i].className.indexOf(className) > 0

--

功能點(diǎn)

瀏覽器窗口大小變化時空幻,頁面中一行里圖片的個數(shù)是固定的烁峭。即圖片列數(shù)不隨瀏覽器窗口大小的變化而變化。

思路:圖片列數(shù)是固定值→使大盒子main的寬度值固定即可→圖片的列數(shù)×一個box的寬

3個步驟:

確定列數(shù):以當(dāng)前的頁面寬度秕铛,除以一個 box 的寬度约郁,結(jié)果取整{Math.floor()}

確定 main 容器的寬度:列數(shù)(即每行中能容納box的個數(shù))乘以一個 box 的寬(也可以這樣寫:oParent.style.width = oBoxW*cols+'px';)

定位第一行盒子:將 box 集合作為數(shù)組取出,遍歷子元素但两,加入入數(shù)組

一個box的寬=圖片寬度165+內(nèi)邊距10×2+邊框1×2 +填充15

在waterfall()中執(zhí)行以下代碼鬓梅,設(shè)置main的寬度以及對齊方式。使用cssText屬性以字符串的形式對其設(shè)置谨湘。offsetWidth計算的是沒有外邊距的盒子寬绽快。

//計算整個頁面顯示的列數(shù)(頁面寬/box的寬)

? ? var oBoxW = oBoxs[0].offsetWidth;//等寬

? ? // console.log(oBoxW);

? ? var cols = Math.floor(document.documentElement.clientWidth / oBoxW)//取整;

? ? // console.log(cols);

? ? //設(shè)置main的寬

? ? oParent.style.cssText = 'width:'+oBoxW*cols+'px;margin:0 auto;'

圖片排序(盒子排列)

3個步驟:

找到上一行里高度最小的盒子(即空隙最大的地方)

把要排列隊列里的第一個的盒子定位到這個空白處

(需要兩個數(shù)值,第一個是上一行最矮盒子的高度【方法:Math.min.apply()】紧阔,第二個是上一行最矮盒子的左邊距【兩種辦法:盒子寬最矮盒子下標(biāo)坊罢;數(shù)組里最小盒子的offsetLeft∩玫ⅲ】) *

更新這一列的高度活孩,最矮元素的高,加上當(dāng)前盒子的高度

--

arrayObject.push() 方法可向數(shù)組的末尾添加一個或多個元素乖仇,并返回新的長度憾儒。

Math.min()返回的是一組數(shù)據(jù)中的最小值。

Math.min.apply(null,hArr)取數(shù)組中的最小值乃沙;apply()接收兩個參數(shù)起趾,一個是函數(shù)運(yùn)行的作用域(this),第一個參數(shù)是null的情況下警儒,this指向window训裆,另一個是參數(shù)數(shù)組。

--

求最矮盒子的下標(biāo)這里寫出getMinhIndex(hArr,minH)函數(shù),或者使用hArr.indexOf(minH)直接返回下標(biāo)值缭保。

getMinhIndex(hArr,minH)這里一旦找到這個最小值汛闸,就返回了索引號;若有多個最小高度值相等艺骂,那么返回的是這個隊列中第一個出現(xiàn)的最小高度值诸老。

//遍歷數(shù)組中的每一個值,若與傳入的特定值相等钳恕,返回該下標(biāo)值别伏。

function getMinhIndex(arr,val){

? ? ? ? for(var i in arr){

? ? ? ? ? ? if(arr[i]==val){

? ? ? ? ? ? ? ? return i;

? ? ? ? ? ? }

? ? ? ? }

? ? }

這樣就找到了上一行最矮的那個盒子以及該盒子所在的索引號。接下來就對下一行第一個盒子進(jìn)行絕對定位忧额。這時候發(fā)現(xiàn)剩下的所有盒子重疊了厘肮。這是因?yàn)樯弦恍兴袌D片的高度hArr[],是固定的那幾個值,所以求得的最小值minH是固定的睦番。即后面的所有盒子都堆在了這個固定最矮圖片的下面类茂。

解決:修改數(shù)組hArr[]里的高度值→改變最小高度值hArr[Index] += oBoxs[i].offsetHeight。最矮元素的高托嚣,加上當(dāng)前盒子的高度巩检,更新這一列的高度。

//waterfall()函數(shù)中執(zhí)行示启。

//先把上一行圖片的高度全都取出來兢哭,然后進(jìn)行存儲。再找出圖片高度的最小值以及該圖片所在的索引對下一個盒子進(jìn)行絕對定位夫嗓。

var hArr = [];//存放每一列高度的數(shù)組

? ? for (var i = 0; i < oBoxs.length; i++) {

? ? ? ? if (i

? ? ? ? ? ? //或hArr[i]=oBoxs[i].offsetHeight;

hArr.push(oBoxs[i].offsetHeight);? ? //獲取第一行盒子的高度并進(jìn)行存放

}else{

//下一行里第一張圖片的定位

var minH = Math.min.apply(null,hArr);//獲取最小值// console.log(minH);

var Index = getMinhIndex(hArr,minH);//獲取索引值

//var Index = hArr.indexOf(minH);

oBoxs[i].style.position = 'absolute';

oBoxs[i].style.top = minH + 'px';//把圖片加上一行中最矮的圖片的底下

oBoxs[i].style.left = oBoxs[Index].offsetLeft + 'px';//px

//修改hArr中的最小值

hArr[Index] += oBoxs[i].offsetHeight;

? ? ? ? }

? ? ? ? console.log(hArr);

? ? }

圖片加載功能

思路:

何時加載:滾動條x向上滾動的距離(scrollTop)與可視區(qū)頁面高度(clientHeight)之和 大于最后一張圖片的距離父元素頂端位置(offsetTop)與盒子高度(offsetHeight )的一半之和迟螺。

offsetTop+offsetHeight / 2是固定值,滾動條向下滾動的距離和頁面向上偏離的距離相等舍咖,知道滾到當(dāng)前隊列中最后一張圖片自身高度的一半或者該圖片剛顯露出來(自定義)開始加載其他的圖片矩父。滾動條向下滾動的距離和頁面的可視區(qū)高度若小于這個固定值,說明沒有滾到需要加載圖片的時候谎仲。

怎么加載:json數(shù)據(jù)交換格式;創(chuàng)造元素并進(jìn)行嵌套(appendChild()方法 語法:parent.appendChild(children))將數(shù)據(jù)信息渲染到頁面中浙垫。

由于數(shù)據(jù)都是從后臺來,這里模擬json格式的數(shù)據(jù)郑诺;首先進(jìn)行遍歷,然后創(chuàng)建盒子杉武,塞到main盒子里辙诞。遍歷給出的數(shù)據(jù),將圖片添加到數(shù)據(jù)塊中渲染出來

首先實(shí)現(xiàn)何時加載功能checkScrollSlide().找出當(dāng)前隊列中的最后一個盒子oBoxs[oBoxs.length - 1],計算數(shù)值時一般計算機(jī)能接受的最小單位是像素轻抱,即整數(shù)飞涂,所以求盒子自身高度值的一半用到Math.floor()。

返回的是布爾型。是否加載较店。

//監(jiān)測是否具備滾動加載數(shù)據(jù)塊的條件

function checkScrollSlide(){

? ? ? ? var oParent = document.getElementById('main');

? ? ? ? var oBoxs = getByClass(oParent,'box');

? ? ? ? var lastBoxH = oBoxs[oBoxs.length - 1].offsetTop + Math.floor(oBoxs[oBoxs.length - 1].offsetHeight / 2);

? ? ? ? // console.log(lastBoxH);最后一個盒子到頁面頂部的距離+自身高度的一半

? ? ? ? var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;//滾動條向上滾動的距離

? ? ? ? // console.log(scrollTop);

? ? ? ? var height = document.body.clientHeight || document.documentElement.clientHeight;//頁面可視區(qū)高度

? ? ? ? // console.log(height);

? ? ? ? return (scrollTop+height>lastBoxH)?true:false;//三元操作符

? ? ? ? // return scrollTop+height>lastBoxH;

? ? }

用到window.onscroll()滾動條滾動事件士八,在頁面加載完畢后即window.onload()里觸發(fā)。

dataInt是一個對象梁呈,以數(shù)組的形式存放數(shù)據(jù)信息婚度。data為數(shù)據(jù)屬性。dataInt.data.length數(shù)據(jù)的個數(shù)官卡。

數(shù)據(jù)加載進(jìn)來后蝗茁,只是這些要渲染的數(shù)據(jù)只是被加到頁面中,并沒有進(jìn)行圖片定位和圖片排序寻咒。會出現(xiàn)重疊和圖片間有空白等現(xiàn)象哮翘。這時,需要再調(diào)用一下waterfall()函數(shù)毛秘。

這樣饭寺,頁面中滾動條不斷下拉時,dataInt對象里幾張圖片就會不斷的進(jìn)行加載叫挟。

var dataInt = {"data":[{"src":'0.jpg'},{"src":'1.jpg'},{"src":'2.jpg'},{"src":'3.jpg'}]};//模擬后臺數(shù)據(jù)

window.onscroll = function () {

? ? ? ? if (checkScrollSlide) {//為真

? ? ? ? ? ? //將數(shù)據(jù)塊渲染到頁面的尾部

? ? ? ? ? ? var oParent = document.getElementById('main');

? ? ? ? ? ? //遍歷數(shù)據(jù)塊

? ? ? ? ? ? for(var i=0;i

? ? ? ? ? ? ? ? //創(chuàng)建存放數(shù)據(jù)塊的盒子并渲染到頁面中

? ? ? ? ? ? ? ? var oBox = document.createElement('div');

? ? ? ? ? ? ? ? oBox.className = 'box';

? ? ? ? ? ? ? ? oParent.appendChild(oBox);

? ? ? ? ? ? ? ? var oPic = document.createElement('div');

? ? ? ? ? ? ? ? oPic.className ='pic';

? ? ? ? ? ? ? ? oBox.appendChild(oPic);

? ? ? ? ? ? ? ? var oImg = document.createElement('img');

? ? ? ? ? ? ? ? //獲取數(shù)據(jù)塊中的文件名

? ? ? ? ? ? ? ? oImg.src="images/"+dataInt.data[i].src;//都存放在固定文件images里

? ? ? ? ? ? ? ? oPic.appendChild(oImg);

? ? ? ? ? ? }

? ? ? ? ? ? waterfall('main','box');

? ? ? ? }

}

問題:

checkScrollSlide調(diào)用的問題

函數(shù)只要是要調(diào)用它進(jìn)行執(zhí)行的艰匙,都必須加括號。此時霞揉,函數(shù)()實(shí)際上等于函數(shù)的返回值旬薯。當(dāng)然,有些沒有返回值适秩,但已經(jīng)執(zhí)行了函數(shù)體內(nèi)的行為绊序,這個是根本,就是說秽荞,只要加括號的骤公,就代表將會執(zhí)行函數(shù)體代碼。

不加括號的扬跋,都是把函數(shù)名稱作為函數(shù)的指針阶捆,用于傳參,此時不是得到函數(shù)的結(jié)果钦听,因?yàn)椴粫\(yùn)行函數(shù)體代碼洒试。它只是傳遞了函數(shù)體所在的地址位置,在需要的時候好找到函數(shù)體去執(zhí)行朴上。

二垒棋、JQuery實(shí)現(xiàn)瀑布流布局

$(window).on('load',function(){

? ? waterfall();

? ? var dataInt = {"data":[{"src":'0.jpg'},{"src":'1.jpg'},{"src":'2.jpg'},{"src":'3.jpg'}]};

? ? $(window).on('scroll',function(){

? ? ? ? if(checkScrollSlide){

? ? ? ? ? ? //創(chuàng)建盒子并添加到頁面中

? ? ? ? ? ? $.each(dataInt.data,function(key,value){

? ? ? ? ? ? ? ? var oBox=$('

').addClass('box').appendTo($('#main'));

? ? ? ? ? ? ? ? var oPic=$('

').addClass('pic').appendTo($(oBox));

// console.log(value);value是dataInt里的對象,即原生js對象痪宰,需加$裝換成JQuery對象才能使用JQuery方法

var oImg=$('').attr('src','images/'+$(value).attr('src')).appendTo($(oPic));

})

waterfall();

}

})

});

function waterfall(){

? ? var $boxs=$('#main>div');//獲取main下的一級div元素

? ? var w = $boxs.eq(0).outerWidth();//一個盒子的寬度包括填充和邊框

? ? var cols = Math.floor($(window).width()/w);

? ? $('#main').width(w*cols).css('margin','0 auto');//設(shè)置main的寬度以及對齊方式

? ? var hArr = [];

? //數(shù)組遍歷

? ? $boxs.each(function(index,value){

? ? ? ? // console.log(index);

? ? ? ? // console.log(value);DOM對象

? ? ? ? var h =$boxs.eq(index).outerHeight();

? ? ? ? if(index

? ? ? ? ? ? hArr[index]=h;

? ? ? ? }else{

? ? ? ? ? ? var minH = Math.min.apply(null,hArr);//最小值

? ? ? ? ? ? var minHIndex = $.inArray(minH,hArr);//索引

? ? ? ? ? ? //console.log(value);value是DOM對象耻姥,需加$裝換成JQuery對象才能使用JQuery方法

? ? ? ? ? ? $(value).css({

? ? ? ? ? ? ? ? 'position':'absolute',

? ? ? ? ? ? ? ? 'top':minH+'px',

? ? ? ? ? ? ? ? 'left':minHIndex*w+'px'

? ? ? ? ? ? })

? ? ? ? ? ? hArr[minHIndex]+=$boxs.eq(index).outerHeight();//更新數(shù)組

? ? ? ? }

? ? })

? ? // console.log(hArr);

}

function checkScrollSlide(){

? ? var $lastBox=$('#main>div').last();//獲取最后一個元素

? ? var lastBoxDis=$lastBox.offset().top+Math.floor($lastBox.outerHeight()/2);

? ? var scrollTop=$(window).scrollTop();//滾動條滾動的距離

? ? var documentH=$(window).height();//頁面可視區(qū)高度

? ? return (lastBoxDis

}

三、CSS3實(shí)現(xiàn)瀑布流布局

根據(jù)盒子的寬度設(shè)置column-width屬性璧亮。這里一個box的寬=圖片寬度165+內(nèi)邊距10×2+邊框1×2 +填充15

這種方式不需要計算,只需要設(shè)置列寬扮饶,瀏覽器自動計算,性能高乍构。但是列寬會隨著瀏覽器窗口的大小進(jìn)行改變甜无,用戶體驗(yàn)不好;另外圖片排序是按照垂直順序排列的蜡吧。最后圖片的加載需要JavaScript實(shí)現(xiàn)毫蚓。

#main{

? ? /*position: relative;*/

? ? -webkit-column-width: 202px;

? ? -moz-column-width: 202px;

? ? -o-column-width: 202px;

? ? column-width: 202px;

}

? ? ? ?

? ? ? ?

? ? ? ?

? ? ? ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市昔善,隨后出現(xiàn)的幾起案子元潘,更是在濱河造成了極大的恐慌,老刑警劉巖君仆,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翩概,死亡現(xiàn)場離奇詭異,居然都是意外死亡返咱,警方通過查閱死者的電腦和手機(jī)钥庇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咖摹,“玉大人评姨,你說我怎么就攤上這事∮┣纾” “怎么了吐句?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長店读。 經(jīng)常有香客問我嗦枢,道長,這世上最難降的妖魔是什么屯断? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任文虏,我火速辦了婚禮,結(jié)果婚禮上殖演,老公的妹妹穿的比我還像新娘氧秘。我一直安慰自己,他們只是感情好趴久,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布敏储。 她就那樣靜靜地躺著,像睡著了一般朋鞍。 火紅的嫁衣襯著肌膚如雪已添。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天滥酥,我揣著相機(jī)與錄音更舞,去河邊找鬼。 笑死坎吻,一個胖子當(dāng)著我的面吹牛缆蝉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瘦真,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼刊头,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了诸尽?” 一聲冷哼從身側(cè)響起原杂,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎您机,沒想到半個月后穿肄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡际看,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年咸产,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仲闽。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡脑溢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赖欣,到底是詐尸還是另有隱情屑彻,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布畏鼓,位于F島的核電站酱酬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏云矫。R本人自食惡果不足惜膳沽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望让禀。 院中可真熱鬧挑社,春花似錦、人聲如沸巡揍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腮敌。三九已至阱当,卻和暖如春俏扩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背弊添。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工录淡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人油坝。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓嫉戚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親澈圈。 傳聞我的和親對象是個殘疾皇子彬檀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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