JS原生瀑布流效果实现
今天早起看了慕课的瀑布流,的确讲的十分详细,也十分的好,我在博客里也就只能给代码加些注释,和说一下思路。建议大家去看一下慕课的瀑布流教程,非常详细,每一个细节都讲的非常好,只要懂js的基础代码,看起来应该不是多大问题,里面没有太难得方法,但自己写不出来还是因为思路上有问题,下面就详细说一下几个重点方法的代码,建议大家去慕课详细学习
html 和css没有太难得地方
<div id="main">//一个main包含了整个页面内容,box用来做一个外容器,img作为图片容器 <div class="box"> <div class="pic"> <img src="img/0.jpg"> </div> </div> <div class="box"> <div class="pic"> <img src="img/0.jpg"> </div> </div> <div>
//css //这里面的填充用padding值,因为offsetheight是包括一个padding而不包括margin的方便以后高度的测量 *{ margin: 0px; padding: 0px; } #main{ position: relative;//在main上设置相对定位,在js给box设置绝对定位,来控制图片位置 } .box{ padding: 15px 0 0 15px; float: left; } .pic{ padding: 10px; border: 1px solid #ccc; border-radius:5px; box-shadow: 0 0 5px #ccc; } .pic img{ width: 168px;//瀑布流统一宽度但不同一高度,高度为自适应就好 height: auto; }
js代码
在我们写js代码之前,我们需要搞明白我们需要什么方法,是否需要封装起来调用,我们第一步要干什么,
那么我们第一步要干什么呢?我们做瀑布流首先要做的是获取到所有小部件也就是box,我们无论做什么处理都是对box的处理或者img的处理,所以要获取到所有的box,所以我们可以把它封装起来
//根据class获取元素 function getbyclass(parent,clsname){//传入父元素和想要的class 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]);//取出传过来相等的classname //push是数组自带的方法 }; return boxarr;返回数组 }
这样我们就得到了我们想要的class,之后该怎么办呢,先从一个box下手,我们需要取得第一排到底有多少个元素,因为之前我们并没有确定我们main的宽度,所以是自适应的也就是说我们把页面缩小,我们每一排的元素也会相应的减少,为了能让瀑布流的代码有更好的应用性,让不同尺寸的图片都可以应用,所以,我们需要手动计算一排究竟可以放多少张图片呢,那如何计算呢?
我们可以算出页面总宽在box的宽,就ok了
var oboxw=oboxs[0].offsetwidth;//box的宽,提到了里面计算了padding的值
var clos=math.floor(document.documentelement.clientwidth/oboxw)//求列数
这样我们就求出了列数,无论图片的宽度如何变,我们都可以算出来
floor是用来取整数的,因为我们的px是没有浮点数类型的避免计算错误,所以取整
oparent.style.csstext='width:'+oboxw*clos+'px; margin :0 auto';
设置main的宽度
我们已经取得了列数之后呢我们第一排的图片肯定是一排宽度相等,长度不一是吧,也就是说,我们第二排的图片需要接上第一排图片的后边,我们不能一排一排操作,但我们可以一个一个操作,怎么操作呢,我们可以取到第一排高度最小的将下一张图片,也就是如果第一排7个,那下一个就是第八个,把第八个图片放在最小高度的图片上,如何实现呢,我们先试想一下,我们首先需要求出第一排中最小,我们有一个math.min求最小,但是呢我们这个函数无法传入用数组,只能是具体的数怎么半呢,apply来扩展作用域
用代码展示下
var harr=[];//每一列高度的值 for (var i = 0; i < oboxs.length; i++) { if(i<clos){//先记录好第一排高度 harr.push(oboxs[i].offsetheight);//放进去 }else{//如果到达第二排,就开始计算 var minh=math.min.apply(math,harr);最小值计算 //为什么可以呢,本来不能传数组,我们通过apply绑定作用域在math上,也就是说还是执行这个函数但是,apply第二个参数需要是数组,所以间接地把参数变成了数组传进去,也就是说我们还是用了math函数但值变成了数组里的值。 //console.log(minh) var index=getminhindex(harr,minh)//获取索引 oboxs[i].style.position="absolute";我们就可以找到,传入数组和最小值 oboxs[i].style.top=minh+"px";那下一张图片的高度救球出来了 oboxs[i].style.left=oboxw*index+"px";左边的距离就是索引乘以元素的宽 harr[index]+=oboxs[i].offsetheight;//我们添加了一个图片后需要刷新数组里的高度,再去寻找下一个最小的,再向他的下面添加图片,一次循环 } }; function getminhindex (arr,val){ for(var i in arr){//在其中找到最小值,返回索引 if(arr[i]==val){ return i; } } }
以上就大体做出了一个瀑布流的样式,就差拖动滚动条加载了,这里面肯定需要后台的支持,在慕课上,老师做了一个伪处理,这里建议看慕课视频,有图解十分清楚,我用语言或图片不太好表达
var dataint={"data":[{"src":'0.jpg'},{"src":'1.jpg'},{"src":'2.jpg'},{"src":'3.jpg'}]}//我们自己写一个json数据 window.onscroll=function(){ if(checkscrollslide){ var oparent=document.getelementbyid("main") //将数据快渲染到当前页面尾部 for (var i = 0; i < dataint.data.length; i++) {//添加 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'); oimg.src='img/'+dataint.data[i].src;//将数据加进去 opic.appendchild(oimg) } waterfall('main','box');//一会看完整代码,这就是刚才那些的封装 } } 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)求出最后一个图片的一半距离页面顶端的距离 var scrolltop=document.body.scrolltop||document.documentelement.scrolltop; var height=document.body.clientheight||document.documentelement.clientheight; return(lastboxh<scrolltop+height)?true:false;//如果页面距离顶部(包括滚轮)的距离比滚轮加页面距离小,那么就返回true }
完整js代码
window.onload=function(){ waterfall('main','box'); //json var dataint={"data":[{"src":'0.jpg'},{"src":'1.jpg'},{"src":'2.jpg'},{"src":'3.jpg'}]} window.onscroll=function(){ if(checkscrollslide){ var oparent=document.getelementbyid("main") //将数据快渲染到当前页面尾部 for (var i = 0; i < dataint.data.length; i++) { 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'); oimg.src='img/'+dataint.data[i].src; opic.appendchild(oimg) } waterfall('main','box'); } } } function waterfall(parent,box){ //将main下所有class为box的元素取出来 var oparent=document.getelementbyid(parent); var oboxs=getbyclass(oparent,box) //console.log(obox.length) //计算整个页面的列数(页面宽/box宽) var oboxw=oboxs[0].offsetwidth; //console.log(oboxw); var clos=math.floor(document.documentelement.clientwidth/oboxw)//求列数 //console.log(clos) //设置main的宽 oparent.style.csstext='width:'+oboxw*clos+'px; margin :0 auto'; var harr=[];//每一列高度的值 for (var i = 0; i < oboxs.length; i++) { if(i<clos){ harr.push(oboxs[i].offsetheight); }else{ var minh=math.min.apply(math,harr); //console.log(minh) var index=getminhindex(harr,minh)//索引 oboxs[i].style.position="absolute"; oboxs[i].style.top=minh+"px"; oboxs[i].style.left=oboxw*index+"px"; harr[index]+=oboxs[i].offsetheight;//更改数组 } }; //console.log(harr) } //根据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]);//取出传过来相等的classname }; return boxarr; } function getminhindex (arr,val){ for(var i in arr){ if(arr[i]==val){ return i; } } } 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) var scrolltop=document.body.scrolltop||document.documentelement.scrolltop; var height=document.body.clientheight||document.documentelement.clientheight; return(lastboxh<scrolltop+height)?true:false; }
我的瀑布流图
以上所述是小编给大家介绍的js原生瀑布流效果实现详解整合,希望对大家有所帮助