手把手教你js原生瀑布流效果实现
手把手教你js原生瀑布流效果实现
什么是瀑布流效果
首先,让我们先看一段动画:
在动画中,我们不难发现,这个动画有以下特点:
- 1.所有的图片的宽度都是一样的
- 2.所有的图片的高度是不一样的
- 3.图片一张挨着一张竖直排列
- 4.鼠标向下滚动,一直不停的加载图片
- 5.浏览器的宽度改变,图片的列数会进行相应的更改
那么这种效果类似现实生活中的瀑布,所以我们叫它瀑布流的效果.
Js原生瀑布流效果的实现
从上述分析中,我们可以把整个效果分为以下四个部分:
- html+css界面搭建
- 瀑布流效果
- 浏览器向下滚动一直加载的效果
- 浏览器宽度改变,图片的列数改变的效果
那么,我们也从这四个分来实现
html+css界面搭建
从效果布局中我们发现,在整体的div标签里面,放置着无数div标签,用于固定每个图片的位置,在每个固定div位置的标签里面又有一个存放图片的div标签,用于图片的定位以及设置边框,在有存放图片的div标签里面放着一个img标签.如下图所示:
布局很简单,也不是这篇文章的重点,所以我就不多说,直接上代码.
html代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>瀑布流</title> <link rel="stylesheet" href="css/index.css"> </head> <body> <div id="outBox"> <div class="box"><div class="pic"><img src="data:images/1.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/2.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/3.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/4.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/5.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/6.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/7.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/8.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/9.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/10.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/11.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/12.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/13.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/1.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/2.jpg" alt=""></div></div> <div class="box"><div class="pic"><img src="data:images/3.jpg" alt=""></div></div> </div> <script src="js/Underscore-min.js"></script> <script src="js/MyFun.js"></script> <script src="js/index.js"></script> </body> </html>
css代码如下:
*{ margin:; padding:; border:; } img{ vertical-align: top; } #outBox{ position: relative; } .box{ padding: 15px 0 0 15px; float: left; } .pic{ padding: 10px; border: 1px solid #ccc; width: 240px; } .pic img { width: 100%; }
效果图如下:
实现瀑布流效果
实现最外层div居中显示
首先,我们可以想到给一个div设置居中显示需要两个步骤:1.给div设置宽度2.给div设置margin属性为auto即可实现div的水平居中显示.那么,我们应该给最外侧大的div设置多少的宽度呢?
我们再来回想一下上述动画效果,我们发现当浏览器宽度变大时,div宽度变宽,显示图片的列数增加,当浏览器宽度变小时,div宽度变窄,显示图片的列数减少.那么我们是不是可以理解为在div的宽度为:当前浏览器宽度下,显示最多的列数乘以div里面用于定位的div的宽度.所以接下来让我们来设置div的宽度及让其居中显示.我的代码每句话都有注释,所以我就不再单独讲解每段代码的含义.
js代码如下:
//首先将大盒子outBox居中排列 //要给大盒子设置宽度,大盒子的宽度为屏幕的宽度/小盒子box的宽度 取整 然后再乘以小盒子的宽度 //获取大盒子 var outBox=$(outBox); //获取大盒子中所有的小盒子 var allBoxs=outBox.children; //由于小盒子的宽度一样,所以随便找到一个小盒子,获取齐宽度 var boxWidth=allBoxs[0].offsetWidth; //获取浏览器的宽度 screenWidth=document.documentElement.clientWidth||document.body.clientWidth; //那么可以计算显示的列数就是浏览器的宽度除以每个小盒子的宽度取整 var cols=parseInt(screenWidth/boxWidth); //设置大盒子的宽度 outBox.style.width=cols*boxWidth +'px'; //设置大盒子的margin值 outBox.style.margin='0 auto';
效果图如下:
对除第一排之外的盒子做定位
首先,我们先了解,为什么是除第一排之外的盒子做定位,因为我们从上述图片中发现,第一排的位置摆放的非常整齐,我们并不需要对他们做定位.
那么,我们如何对第一排之外的盒子做定位呢?有人则认为从左至右逐一排列即可.那么由于所有的盒子高度不一样,我们假设一种情况所有的第一列的高度最大,第二列的高度最小,其它列依次增加,当我们排列的多了,会不会出现如下图所示非常丑陋的布局?
答案是肯定的,因为每张照片的长度都不一样,任何排列组合都有可能,所以我们不能从左到右依次排列,当然也不能从右至左依次排列.
接下来让我们想想,如果有一个容器,我们往里面放大小不等的物品,放进去的物品是不是会落到高度最小的那个位置?(如果理解不了的话,可以自己找个容器往里面丢东西试试.)所以我们排放图片也基于这个原理,把图片放高度最低的列,放置之后,更新列高为原列高+放置图片的高度.依次来放置图片即可.代码实现如下:
//遍历所有的box,然后将第一排(前cols个盒子的高度放入数组中) //创建一个空数组 var boxHeightArr=[]; //创建两个临时变量最小的高度以及盒子的高度 var minHeight=0,boxHeight=0; //遍历所有的盒子 for(var i=0;i<allBoxs.length;i++){ //获取遍历到每个盒子的高度 boxHeight=allBoxs[i].offsetHeight; if(i<cols){//讲第一排的高度放入数组中 boxHeightArr.push(boxHeight); }else { //然后将第一排后面的所有的元素放入之前数组中高度最小的那一列 //获取数组中最小的高度 minHeight=_.min(boxHeightArr); //计算最小高度的下标,通过遍历实现 var minIndex=getIndexByValue(boxHeightArr,minHeight); //设置当前盒子的样式,首先为固定定位 allBoxs[i].style.position='absolute'; //设置当前盒子的top,为最小高度 allBoxs[i].style.top= minHeight +'px'; //设置当前盒子的left为最小高度的下标乘以盒子的宽度,如果第三个为最小高度,那么当前盒子的left和第三个left一样,为3*盒子的宽度,因为盒子的宽度都一样 allBoxs[i].style.left= minIndex*boxWidth+'px'; //将数组中最小盒子的高度更新为当前高度+原来高度 boxHeightArr[minIndex]+=allBoxs[i].offsetHeight; } } } /* * 作用:通过数组中某一个元素,返回其在数组的索引 * 用法:getIndexByValue(数组,数组元素) * 返回值:返回数组元素在数组中的索引 * */ function getIndexByValue(arr,value) { //遍历数组 for(var i=0;i<arr.length;i++){ //输入数组中第i个元素的值和value一样,则返回i,i为最小宽度的下标 if(arr[i]==value){ return i; } } }
效果如下:
实现浏览器向下滚动一直加载的效果
首先,我们要先监听到浏览器向下滚动事件.其次我们需要计算出什么时候需要加载盒子.那么我们就定义一下,当最后一个盒子显示出来之后,我们就开始加载,那么最后一个盒子显示出来的判断条件是什么呢?请看下图.
从图中我们不难看出,当最后一个盒子的offsetTop值大于浏览器的高度+浏览器滚动的高度时,我们是在浏览器中看不到最后一个盒子的,所以最后一个盒子显示出来的条件为最后一个盒子的offsettop值大于浏览器的高度+浏览器滚动的高度.
接下来我们要实现自动创建盒子,这些dom的基本的知识,想必大家都很熟悉,那么问题来了,我们如何给盒子里面的img标签设置图片呢?当然,实际开发中我们是通过向服务器获取的方式获得图片的地址,但是现在这边文档的重点不是这个,所以我就随便创建了一个json,然后把数据事先写在json里面,需要用到的时候调用一下就行了.
判断是否需要加载的代码如下:
/* * 功能:判断是否需要加载图片 * 用法:willBeLoad() * 返回值:true 需要加载 false不需要加载 * */ function willBeLoad() { //1.先获取到最后一张照片,然后看它是否显示出来.如果显示则返回true,否则返回false //如果图片已经显示出来,那么这个图片到顶部的距离offsettop <屏幕的高度+滚动的高度 //获取所有的照片 var allBoxs=document.getElementsByClassName('box'); //获取最后一张图片,最后一张图片的下标为数组的长度减一 var lastBox=allBoxs[allBoxs.length-1]; //获取最后一张图片的offsetTop值 var lastBoxDis=lastBox.offsetTop; //获取屏幕的高度,这里需要适配不同的浏览器,所以使用||兼容一下 var screenHeight=document.documentElement.clientHeight||document.body.clientHeight; //获取滚动的高度 var scrollHeight=scroll().top; //判断,返回结果 if(lastBoxDis<=scrollHeight+screenHeight){ return true; }else { return false; } }
实现无限加载的js代码如下:
//实现向下滚动,无线加载图片 //监听滚动事件 window.onscroll=function () { if(willBeLoad()){//需要加载 //制造点假数据 var dataArr=[ {src:'1.jpg'}, {src:'5.jpg'}, {src:'3.jpg'}, {src:'4.jpg'}, {src:'2.jpg'}, {src:'9.jpg'}, {src:'8.jpg'}, {src:'6.jpg'}, {src:'7.jpg'}, {src:'10.jpg'}, {src:'12.jpg'}, {src:'13.jpg'}, ] //遍历数据 for(var i=0;i<dataArr.length;i++){ //创建一个新的盒子 var newBox=document.createElement('div'); //新盒子的className为box,和其它的样式一样 newBox.className='box'; //添加新盒子 $('outBox').appendChild(newBox); //创建一个新的pic盒子 var newPic=document.createElement('div'); //新盒子的className为pic,和其它的样式一样 newPic.className='pic'; //添加新盒子 newBox.appendChild(newPic); //创建一个img标签 var newImg=document.createElement('img'); //img标签的src是哪个从json数据中取出 newImg.src='images/'+dataArr[i].src; //添加新的img标签 newPic.appendChild(newImg); } //所有的盒子都创建完成之后,再执行一次瀑布流方法,否则新创建的标签不会实现瀑布流的效果 waterFall('outBox',screenWidth); } }
效果图如下:
浏览器宽度改变,图片的列数改变的效果
首先要监听浏览器宽度改变事件,然后当浏览器宽度改变之后,重新获取宽度,重新计算可以摆放的列数,然后加载瀑布流方法,这个比较简单,不多说,直接看代码即可
js代码如下:
window.onresize=function () {//监听窗口改变事件 //获取浏览器的宽度 screenWidth=document.documentElement.clientWidth||document.body.clientWidth; //重新执行瀑布流方法 waterFall('outBox',screenWidth); }
至此,所谓的js原生瀑布流效果已经实现,相信你看了这篇博客之后也发现js原生瀑布流并没有想象中的那么难,关键是思路要正确.
手把手教你js原生瀑布流效果实现的更多相关文章
- js图片瀑布流效果
要实现图片瀑布流效果,首先得准备几张图片. html的部分比较简单就是将图片加载到浏览器就可以了 代码如下(注意放的图片多一点要不然之后无法滑动鼠标就无法达到瀑布流效果): <!DOCTYPE ...
- js原生瀑布流
背景: 1.在移动端开发,jq文件是显得非常庞大的,所以所有效果尽量用HTML5和原生js实现. 2.本次瀑布流是固定列数,采用非浮动的另外一种瀑布流思想实现的. 3.本次数据来源是json接口 4. ...
- 原生js实现瀑布流效果
参考此篇:https://segmentfault.com/a/1190000012621936 以下为个人测试中: css: .masonry{ width:100%; } .item{ posit ...
- JS+PHP瀑布流效果(二)
<!-- 加载商品 --><script> //用户拖动滚动条,达到底部时ajax加载一次数据 var loading = $("#loading&quo ...
- js 图片瀑布流效果实现
/** * Created by wwtliu on 14/9/5. */$(document).ready(function(){ $(window).on("load",fun ...
- JS+PHP瀑布流效果
miai.php,代码如下: $link = mysql_connect("localhost","root",""); //连接数据库 $ ...
- 原生JS实现瀑布流
浏览网页的时候经常会遇到瀑布流布局的网站.也许有些读者不了解瀑布流.瀑布流,又称瀑布流式布局.是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数 ...
- js 实现图片瀑布流效果,可更改配置参数 带完整版解析代码[waterFall.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS实现图片瀑布流效果 页面需求 1 ...
- 利用JS实现简单的瀑布流效果
哈哈, 我又来啦, 在这一段时间里, 我简单的学习了一下javascript(JS), 虽然不是很懂啦, 但是我也简单的尝试着做了点小东西, 就比如现在流行的瀑布流效果, 经过我的努力终于成功的完成了 ...
随机推荐
- 针对access数据库的增删改查
1.执行查询操作:(ExecuteReader方法) string myConnectionString = "Provider = Microsoft.Jet.OLEDB.4.0;Data ...
- Jasper_filter data_pass field data from main to sub to filter some data
main report: 1 add variable <variable name="Variable_rule" class="java.lang.String ...
- oldboy第二天学习
一.上课体验及感受 第二天上课了,从循环到队列,感觉都可以接受,但是当循环遇到队列之后感觉脑袋就有点不够用了.不知道是因为萌新的问题.每个人都这样,还是个人能力不行.总而言之加油努力吧!! 二.循环, ...
- Java比较两个日期的大小
public static String getComparedSBQDate(String yxqq,String starttime){ String str = starttime; Simpl ...
- Cracking the coding interview--Q1.7
原文 Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column are s ...
- 强大疯狂的qttools
就是有点疑惑,为什么不整合到QT主项目中呢? 有空好好看看: https://github.com/qtproject/qttools/tree/dev/src ------------------- ...
- Xamarin devexpress Grid
Devexpress 提供了datagrid 控件对于xamarin 进行支持.整个世界美好了,已经无法用语言来形容一个 被列表控件折磨的要死的人看到熟悉的图标时候的激动了.还有一点引用官网的原话: ...
- 手机低端市场,联发科 vs 高通
联发科(MTK) 是山寨机的源头,我过去曾经鄙视他,现在来了180度转弯. 其实联发科是台湾的上市公司,手机如此复杂的东西,当年 联发科能把基础的手机做出来,而后小山寨厂改改外形,配件就能出若干款手机 ...
- 【HDOJ】3184 All Can Do
简单数学题. #include <cstdio> #include <cstring> #include <cstdlib> int main() { int t; ...
- android设置组件所占的比例
当我们使用linearlayout线性布局,放置三个textview空间,设置android:layout_width属性为wrap_content,并分别设置android:layout_weigh ...