瀑布流小实例
网站备案终于下来了,等了十几天,不容易呀,顺便搞了个免费的https证书,把评论也换成畅言的了,来必力太挫了,ui看见想打人系列。
瀑布流,又称瀑布流式布局。其特点是随着页面滚动条向下滚动,不断加载数据块并附加至当前尾部。从Pinterest开始兴起,国内也有许多网站采用这种样式,不过大多数为了节约代码采用的是等宽等高的样式。今天我要演示的是等宽不等高如何进行瀑布流加载。
html结构
由于我们这里瀑布流的布局是采用绝对定位的,所以html结构非常简单,加载的html都是通过js操控的。
<main>
<div id="main">
<div class="pin"> //js生成的
<div class="box">
<img src="./images/0.jpg">
</div>
</div>
</div>
</main>
css
css没什么好说的,也是非常简单,由于其等宽不等高的性质,我们把.box的宽度都定死,这里由于要整体居中,由于.pin
有padding-left:14px;
,故而而把#main
设置了left: -7px;
让其整体居中一下。
*{padding: 0;margin:0;}
#main{
position: relative;
left: -7px;
}
.pin{
padding: 14px 0 0 14px;
float:left;
}
.box{
padding: 10px;
border:1px solid #ccc;
box-shadow: 0 0 6px #ccc;
border-radius: 5px;
width: 182px;
box-sizing: border-box;
}
.box img{
width:100%;
height:auto;
}
js
瀑布流的重点部分就在js啦。
首先我们写一个创建节点的函数,用于创建.pin
、.box
和img,createDom传入父节点和img的src。
function createDom(obj,src){
var oDiv = document.createElement('div');
oDiv.className = 'pin';
var oBox = document.createElement('div');
oBox.className = 'box';
var oImg = document.createElement('img');
oImg.src = './images/'+src;
oBox.appendChild(oImg);
oDiv.appendChild(oBox);
obj.appendChild(oDiv);
}
此时我们的页面上还空无一物呢,这时需要我们模拟后端数据,遍历json调用createDom生成dom节点。
var oParent = document.getElementById('main');
var dataInt = [];
for(var i=0;i<98;i++){
dataInt.push({'src':i+'.jpg'});
if(i<50){
createDom(oParent,dataInt[i].src);
}
}
此时样式大致是这样的
然后我们再写一个定位的函数,让其一一队列排齐。
由于是等宽的,我们获取其中一个.pin
的宽度,然后让可视窗口宽度除以这个宽度,通过向下取整获得一行能放下.pin
的个数。用.pin
的宽度*
个数得到它父容器应该有的宽度赋给父容器,然后让其居中显示,此时整体就居中了。
我们再把所有的.pin
遍历一遍,先把第一行的所有.pin
的高度装在pinHarr数组里面。由于瀑布流是一一对齐的,每一行的第一个都是在最矮的那一列下面。
所以第二行的第一个.pin
应该在它的上一行最矮的那个.pin
下面,所以不是第一行的话,我们给其全部绝对定位,我们就找到第一行中.pin
的最小高度,取得它的索引,这样就得到最矮的那个.pin
,我们取得它的高度和索引,把第二行的这个.pin
的top赋值第一行中.pin
最小高度,left赋值第一行最矮的.pin
的索引*.pin
的宽度,这样第二行的第一个就在第一行的最矮的那个.pin
下面且对齐。
最后我们把pinHarr中最小的那个高度换成最小高度加上新增的这个.pin
高度(简单来说就是列高),此时最小高度变化了,我们下一次还是找最小高度放.pin
,以此类推,每次放置.pin
都是找最矮那一列放置。这样就实现了等宽不等高的对其布局了。
function waterfall(parent,pin){
var aPin = parent.querySelectorAll(pin);
var iPiw = aPin[0].offsetWidth;
var num = Math.floor(document.documentElement.clientWidth/iPiw);
parent.style.cssText = 'width:'+num*iPiw+'px;margin:0 auto;';
var pinHarr = [];
aPin.forEach(function(el,index){
var pinH = el.offsetHeight;
if(index<num){
pinHarr[index] = pinH;
}else{
var minH = Math.min.apply(null,pinHarr);
var minindex = pinHarr.findIndex(function(num){
return minH===num;
});
el.style.position = 'absolute';
el.style.left = iPiw*minindex +'px';
el.style.top = minH+'px';
pinHarr[minindex] = minH+el.offsetHeight;
}
});
接下来等页面生成的最后一个img加载出来后我们调用这个函数,布局就完成了。
oParent.getElementsByClassName('pin')[49].getElementsByTagName('img')[0].onload = function(){
waterfall(oParent,'.pin');
}
当页面滚动到底部时,我们还要让其生成新的dom,将其放在底部。
我们先写一个判断函数,判断滚动条滚动时到达底部没有,没有就返回false,有就返回true。
function isBottom(){
var aPin = oParent.querySelectorAll('.pin');
var lastPinh = aPin[aPin.length-1].offsetTop+Math.floor(aPin[aPin.length-1].offsetHeight/2);
var Sh = document.documentElement.scrollTop||document.body.scrollTop;
var Dh = document.documentElement.clientHeight;
return lastPinh<Sh+Dh?true:false;
}
最后我们添加滚动事件,当到达底部时,我们遍历json,用createDom生成dom添加到#main
底部,然后调用waterfall,让其让其一一队列排齐。
window.onscroll = function(){
if(isBottom()){
dataInt.forEach(function(val){
createDom(oParent,val.src);
});
waterfall(oParent,'.pin');
}
}
这样,一个等宽不等高的无限加载的瀑布流就实现了。效果如下:
近期评论