通过使用JavaScript来实现瀑布流,我们可以对JS了解的更加深刻。
我们知道在不使用浮动属性的时候,图片会按照在html代码里的顺序依次排列,而我们想要实现瀑布流,就应该把页面上每行都固定住,然后求出高度最短的那个,将第二排的图片放在最短的那个图片下面,再继续找下一个高度最短的图片,依次操作,就会有瀑布流的效果。
本例子中基本的html和css代码就不再贴上来,我们放了一些图片在html里,而且给每个图片区域的宽度都设置为相同。布局如下所示。
<div id="container">
<div class="box">
<div class="box_img">
<img src="h5img/1.jpg">
</div>
</div>
</div>
1)首先如何将页面上放置着图片的每行固定住而不是随着屏幕宽度的变化而变化呢,思路就是求出本行里所有图片区域的宽度和个数,将内容区域宽度设置为图片区域的宽度和个数相乘的结果,而图片区域的个数怎么求到呢?因为每个图片区域的宽度都相同,只要将屏幕宽度除以图片区域宽度就得到了。
通过文字来叙述思路貌似很晦涩,我们还是直接看代码吧,相信你很快会看出思路
首先我们定义一个方法来获取到所有的图片区域,将其存储在数组里,这一点是很有必要的,因为在后面我们还需要多次用到图片区域,这样做会很方便。
parent调用getElementsByTagName()的参数设置为*,表示要获取所有parent下面的元素,本例中也就是所有的box。
function getChildElemnets(parent,content){
//获取所有的box并且存储在数组里
var childAttrs=[];
var childNodes=parent.getElementsByTagName("*");
for(var i=0;i<childNodes.length;i++){
if (childNodes[i].className ==content){
childAttrs.push(childNodes[i]);
}
}
return childAttrs;
}
然后再按照上面讲的思路将内容宽度固定
function getElements(parent,content){
var containerPar=document.getElementById(parent);
var conBox=getChildElemnets(containerPar,content);//获取所有的box
var imgWidth=conBox[0].offsetWidth;//每个box的宽度,因为是等宽的,所以随便一个的宽度也就等于每一个的宽度
var imgCounts=Math.floor(document.documentElement.clientWidth/imgWidth);//每一行的图片数目,即屏幕宽度除以图片宽度,并且转换为整数
containerPar.style.cssText="width:"+imgWidth*imgCounts+"px;margin:0 auto";//将container固定住
}
2)继续在这个方法里,接下来我们对第一行所有的box进行遍历获取到它们所有的高度,通过Math.min方法来求出最短的那个,并获取到最短的这个的位置数(在本行中是第几个),然后将第一行以外的下一个图片放到它的下面。
怎么将其放到最短图片的下面呢?只要将其position属性设置为绝对位置保持不动,然后将其距离页面顶部的距离设置为最短图片的高度,将其距离页面左边的距离设置为最短图片距离左边的距离,就实现了这个功能。
最后非常重要的一点,不要忘记了将最短高度所在位置现在的高度设置为两个box高度之和,然后才能正确的进行下一次比较,寻找新的最短高度box,继续将下一个图片插入。
var boxHeightArr=[];//获取所有的box高度以便找出最短的那个
for(var i=0;i<conBox.length;i++){
if (i<imgCounts){//获取第一行所有的box高度
boxHeightArr[i]=conBox[i].offsetHeight;
}else {
//以下几行是实现插入图片进入较短图片的实现代码
var minBoxHeight=Math.min.apply(null,boxHeightArr);
var minBoxIndex=getMinBoxHeightIndex(boxHeightArr,minBoxHeight);//最短的box所在的位置数
conBox[i].style.position="absolute";
conBox[i].style.top=minBoxHeight+"px";//距离屏幕顶部的距离就是最短图片的高度,这样就把它放在了最短的图片下面
conBox[i].style.left=conBox[minBoxIndex].offsetLeft+"px";
//距屏幕左距离就是它所插入图片位置距离屏幕左边的距离
boxHeightArr[minBoxIndex]=boxHeightArr[minBoxIndex]+conBox[i].offsetHeight;//刷新插入图片所在位置的高度
}
}
}
function getMinBoxHeightIndex(boxHeightAttr,minboxHeight){
for(var i in boxHeightAttr){
if (boxHeightAttr[i]==minboxHeight){
return i;//找到最短的box所在的位置数
}
}
}
这样基本的瀑布流效果就实现了,下面是我的测试效果。
3)我们在网上浏览图片的时候都知道,到页面底部会刷新数据,出来新的图片,那么底部刷新是怎么实现的呢?
思路是这样的,当处于最底部的时候,我们获取到当前滚动条的高度,屏幕高度,还有当前最高的图片距离屏幕顶部的高度。由上面我们实现瀑布流的方法可以知道,最后高度最大的那个应是box数组里最后的那个box。
那么当最高图片距离顶部的距离小于滚动条高度与屏幕高度之和,也就到了页面底部,就应该是进行刷新数据的时刻到了!
function checkScroolHeight(){
var conPar=document.getElementById("container");
var conImg=getChildElemnets(conPar,"box");//获取所有的box
var lastBoxHeight=conImg[conImg.length-1].offsetTop;//获取最后那个高度最高的图片距离屏幕顶部的距离
var scroolHeight=document.documentElement.scrollTop||document.body.scrollTop;//获取滚动条滚动了多高
var pageHeight=document.documentElement.clientHeight||document.body.clientHeight;//获取屏幕高度
if (lastBoxHeight<(scroolHeight+pageHeight)){
return true;
}
}
一般我们是通过后端语言来进行网络获取,通过网络返回的JSON数据进行解析资源,然后将获取到的资源插入页面里面。这里我们为了测试,自己模拟了一段JSON数据,并放进一些图片资源,只需要直接获取就行了
关于createElement()的使用很简单,可以通过clssName属性设置其class的值,最后通过父级的appendChild()将其放进父级元素里面。
var urlData= {"data":[{"src":"1.jpg"},{"src":"2.jpg"},{"src":"3.jpg"},{"src":"4.jpg"},{"src":"5.jpg"},{"src":"6.jpg"}]};
window.οnscrοll=function(){
if (checkScroolHeight()){
var content=document.getElementById("container");
for(var i=0;i<urlData.data.length;i++){
var contentDiv=document.createElement("div");
contentDiv.className="box";
content.appendChild(contentDiv);
var boxImgDiv=document.createElement("div");
boxImgDiv.className="box_img";
contentDiv.appendChild(boxImgDiv);
var imgDiv=document.createElement("img");
imgDiv.src="h5img/"+urlData.data[i].src;
boxImgDiv.appendChild(imgDiv);
}
getElements("container","box");
}
};
};
这样,我们滑动鼠标到页面底部,就会自动进行数据刷新,而刷新出的数据自然就是我们自己模拟的JSON里的数据了。