JS原生瀑布流效果实现


Posted in Javascript onApril 26, 2019

今天早起看了慕课的瀑布流,的确讲的十分详细,也十分的好,我在博客里也就只能给代码加些注释,和说一下思路。建议大家去看一下慕课的瀑布流教程,非常详细,每一个细节都讲的非常好,只要懂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原生瀑布流效果实现

以上所述是小编给大家介绍的JS原生瀑布流效果实现详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Javascript 篱式条件判断
Aug 22 Javascript
JavaScript通过字典进行字符串翻译转换的方法
Mar 19 Javascript
继续学习javascript闭包
Dec 03 Javascript
JavaScript实现向select下拉框中添加和删除元素的方法
Mar 07 Javascript
微信小程序实现的涂鸦功能示例【附源码下载】
Jan 12 Javascript
详解使用 Node.js 开发简单的脚手架工具
Jun 08 Javascript
微信小程序动画(Animation)的实现及执行步骤
Oct 28 Javascript
vue基础之data存储数据及v-for循环用法示例
Mar 08 Javascript
webpack-mvc 传统多页面组件化开发详解
May 07 Javascript
mpvue实现微信小程序快递单号查询代码
Apr 03 Javascript
JavaScript逻辑运算符相关总结
Sep 04 Javascript
一文了解JavaScript用Element Traversal新属性遍历子元素
Nov 27 Javascript
Vue基于vuex、axios拦截器实现loading效果及axios的安装配置
Apr 26 #Javascript
详解auto-vue-file:一个自动创建vue组件的包
Apr 26 #Javascript
vue组件间的参数传递实例详解
Apr 26 #Javascript
详解VUE前端按钮权限控制
Apr 26 #Javascript
微信小程序开发之点击按钮退出小程序的实现方法
Apr 26 #Javascript
js最实用string(字符串)类型的使用及截取与拼接详解
Apr 26 #Javascript
微信小程序实现的绘制table表格功能示例
Apr 26 #Javascript
You might like
谈一谈收音机的高放电路
2021/03/02 无线电
模拟OICQ的实现思路和核心程序(三)
2006/10/09 PHP
js 父窗口控制子窗口的行为-打开,关闭,重定位,回复
2010/04/20 Javascript
JavaScript 学习历程和心得分享
2010/12/12 Javascript
IE的有条件注释判定IE版本详解(附实例代码)
2012/01/04 Javascript
jQuery事件 delegate()使用方法介绍
2012/10/30 Javascript
JS中的this变量的使用介绍
2013/10/21 Javascript
js中判断对象是否为空的三种实现方法
2013/12/23 Javascript
轻松创建nodejs服务器(8):非阻塞是如何实现的
2014/12/18 NodeJs
浅谈JavaScript中的Math.atan()方法的使用
2015/06/14 Javascript
聊一聊JavaScript作用域和作用域链
2016/05/03 Javascript
D3.js实现柱状图的方法详解
2016/09/21 Javascript
js数组操作方法总结(必看篇)
2016/11/22 Javascript
Vue + Webpack + Vue-loader学习教程之相关配置篇
2017/03/14 Javascript
基于 webpack2 实现的多入口项目脚手架详解
2017/06/26 Javascript
nodeJs爬虫的技术点总结
2018/05/13 NodeJs
javascript数组常见操作方法实例总结【连接、添加、删除、去重、排序等】
2019/06/13 Javascript
详解Vscode中使用Eslint终极配置大全
2019/11/08 Javascript
微信小程序 SOTER 生物认证DEMO 指纹识别功能
2019/12/13 Javascript
python通过文件头判断文件类型
2015/10/30 Python
Python中模块string.py详解
2017/03/12 Python
Python中的浮点数原理与运算分析
2017/10/12 Python
python 简单照相机调用系统摄像头实现方法 pygame
2018/08/03 Python
python类中super() 的使用解析
2019/12/19 Python
CSS3的transition和animation的用法实例介绍
2014/08/20 HTML / CSS
CSS3 函数技巧 用css 实现js实现的事情(clac Counters Tooltip)
2017/08/15 HTML / CSS
捷克电器和DJ设备网上商店:Electronic-star
2017/07/18 全球购物
Manduka官网:瑜伽垫、瑜伽毛巾和服装
2018/07/02 全球购物
Unix如何在一行中运行多个命令
2015/05/29 面试题
计算机学生的自我评价分享
2014/02/18 职场文书
高三毕业典礼演讲稿
2014/05/13 职场文书
常务副总经理任命书
2014/06/05 职场文书
建筑工地质量标语
2014/06/12 职场文书
2014离婚协议书范文两篇
2014/09/15 职场文书
医务人员岗前培训心得体会
2016/01/08 职场文书
css中:last-child不生效的解决方法
2022/08/05 HTML / CSS