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 相关文章推荐
js中arguments的用法(实例讲解)
Nov 30 Javascript
浅谈Javascript变量作用域问题
Dec 16 Javascript
实例讲解JS中setTimeout()的用法
Jan 28 Javascript
常用原生JS兼容性写法汇总
Apr 27 Javascript
微信小程序 弹框和模态框实现代码
Mar 10 Javascript
vue-cli+webpack记事本项目创建
Apr 01 Javascript
原生JS实现图片网格式渐显、渐隐效果
Jun 05 Javascript
JavaScript初学者必看“new”
Jun 12 Javascript
JS实现求5的阶乘示例
Jan 21 Javascript
Layui弹框中数据表格中可双击选择一条数据的实现
May 06 Javascript
js事件机制----捕获与冒泡机制实例分析
May 22 Javascript
JSON 入门教程基础篇 json入门学习笔记
Sep 22 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
PHP中的cookie不用刷新就生效的方法
2012/02/04 PHP
php数据库配置文件一般做法分享
2012/07/07 PHP
win7 wamp 64位 php环境开启curl服务遇到的问题及解决方法
2018/09/16 PHP
用于table内容排序
2006/07/21 Javascript
javascript实现unicode和字符的互相转换
2007/07/18 Javascript
Javascript表格翻页效果的具体实现
2013/10/05 Javascript
使用js判断当前时区TimeZone是否是夏令时
2014/02/23 Javascript
jQuery定义插件的方法
2015/12/18 Javascript
深入解析js轮播插件核心代码的实现过程
2017/04/14 Javascript
JS给按钮添加跳转功能类似a标签
2017/05/30 Javascript
jquery实现直播视频弹幕效果
2020/02/25 jQuery
Vue2.4+新增属性.sync、$attrs、$listeners的具体使用
2020/03/08 Javascript
Vue 防止短时间内连续点击后多次触发请求的操作
2020/11/11 Javascript
[02:06]DOTA2英雄基础教程 暗影萨满
2013/12/16 DOTA
Python getopt模块处理命令行选项实例
2014/05/13 Python
PyTorch学习笔记之回归实战
2018/05/28 Python
Flask框架 CSRF 保护实现方法详解
2019/10/30 Python
Python实现i人事自动打卡的示例代码
2020/01/09 Python
Tensorflow实现多GPU并行方式
2020/02/03 Python
python字符串替换re.sub()实例解析
2020/02/09 Python
15行Python代码实现免费发送手机短信推送消息功能
2020/02/27 Python
详解CSS3 Media Queries中媒体属性的使用
2016/02/29 HTML / CSS
KLOOK客路:发现更好玩的世界,预订独一无二的旅行体验
2016/12/16 全球购物
德国亚洲食品网上商店:asiafoodland.de
2019/12/28 全球购物
如何利用cmp命令比较文件
2013/09/23 面试题
个人对照检查材料
2014/02/12 职场文书
秋游活动策划方案
2014/02/16 职场文书
《曹刿论战》教学反思
2014/03/02 职场文书
人事科岗位职责范本
2014/03/02 职场文书
庆六一文艺汇演活动方案
2014/08/26 职场文书
酒店优秀员工推荐信
2015/03/24 职场文书
员工升职自荐信
2015/03/27 职场文书
交通事故被告代理词
2015/05/23 职场文书
就业推荐表院系意见
2015/06/05 职场文书
深入浅析python3 依赖倒置原则(示例代码)
2021/07/09 Python
Nginx配置文件详解以及优化建议指南
2021/09/15 Servers