html結(jié)構(gòu)
(Emmet)
(div.box>div.pic>img[src="images/$.jpg"])*23
? ? ? ? ? ?
? ? ? ? ? ?
? ? ? ? ? ?
? ? ? ? ? ?
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=$('
? ? ? ? ? ? ? ? var oPic=$('
// 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;
}
? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ?