导读:瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinterest,逐渐在国内流行开来。国内大多数清新站基本为这类风格,像花瓣网、蘑菇街、美丽说等。

  改进版的代码见:github,可以与现有的进行对比,见文章末尾。

  最近在好多地方看到瀑布流的字眼,感觉真的很不错,于是就想自己能不能写一个呢,而且是响应式的。经过将近两天的研究,终于写出来了,先传几张图给大家看看最终的效果:

    

  随着浏览器页面的大小调整。布局从四列逐渐变成三列两列,甚至是一列(图像的块的宽度是保持不变的)。

  在我看来,在复杂的程序其实都是由很简单的函数组合在一起的,另外有一些经常用到的部分也会被抽取出来当做一个新的函数。然后,为了封装,会将一些变量也封装起来,然后通过外部传递进来,最后就成了我们现在看到的。其实一开始,很少人能够确定要怎么写,且能确定需要传进哪些参数。一开始只能大概确定需要做哪些,需要哪些函数,写着写着,发现缺了在添加就好了。至少我自己是这样的(也许是我现在太渣了)。

  好了,接下来说一说 具体实现的过程。请结合源码来看。

  第一步:我们需要创建这些图像块,也就是源码中的createDiv函数。这里为了节省性能,我们采用字符串的形式,而不用createElement等这些函数。然后这里你会发现一个问题,我们生成的块的大小是一样的。这时候,我们就需要用到random函数了。通过该函数来生成高度不一样的图像块。

  第二步:怎样确定图像的列数和怎样让他随着页面的改变而改变自己的列数。这里我们就得用到widthchange函数。首先图像块的父容器的外边距是20px;因此总的宽度就得减去40(这里以浏览器页面来算)。然后再根据图像块的宽度,来确定每一列之间的列数和间距。

  第三步:设置样式setStyle。图像块的大小确定之后,我们得设置图像块的样式,比如大小,间距等等。

  第四步:把上面的结合起来,进行封装就好了。

-------------------------------------------------------------------------------------------------------------------

  但是呢,我们得考虑一个问题,就是图片太多了,我们不可能一次让所有图片都下载,这样会影响网页的性能和用户的体验。那么有没有什么好的办法呢?我们只让可视区的图片显示就好了。那怎么实现呢,我们来分析下

  1、这里涉及到上面的createDiv函数,得先说清楚。我们得将img的src的地址设为其他地址或为空。然后再自定义一个data-src属性,属性值为图片的地址。

  2、可视区的图片显示。也就是我们得先判断图片的位置是不是在这个可视区内,这里就得用到pageY,show函数,这些函数会用到offsetTop,scrollTop和clientHeight等这些属性。

  3、如果在的话,就将data-src的值赋给src,并且将其从数组中去掉,表示该图片已经被加载。

  4、最后将函数进行修改,封装。再绑定好各个事件就大功告成了。

  最后附上源码供大家研究,如果觉得好的话,可以加我的个人微信公众号,这样你就不用访问博客就可以获取相关信息。

  公众号名字:JavaScript学习与实践

  微信号:learnpracticeJs

  公众号二维码:

欢迎大家关注我的公众号,你的关注就是我最大的支持。

源代码:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>瀑布流 by huansky</title>
<style>
#container{
position: relative;
top:20px;
margin: 20px 20px;
background: #c00;
}
#container .wf{
position: absolute;
border: 1px solid #ccc;
font-size: 40px;
border-radius: 10px;
overflow: hidden;
}
p{
margin: 0px;
padding: 0px;
}
h1{
text-align: center;
}
</style>
</head>
<body>
<h1>瀑布流 by huansky</h1>
<div id="container">54454</div>
</body>
<script >
function wf(obj){
this.colHeight=[]; //每一列的高
this.colLeft=[]; //每一列的位置; 因为列是等宽的,所以每一列的位置也是固定的。
this.flag=0; //标志位,包含图片的容器只需要创建一次
this.imgWidth=obj.wth; //设置每一列的宽度
this.id=document.getElementById(obj.id); //获取最外层的容器
this.classname=document.getElementsByClassName(obj.classname); //获取瀑布流的类名
//变量一定要在init()之前给定义,不能放在init()之后
this.init(); //初始化
}
wf.prototype={
//获取m到n的随机值
random:function(m,n){
return Math.ceil(Math.random()*(n-m)+m);
}, //最小值的下标
getMinCol:function(arr){
var ca = arr,cl = arr.length,temp = ca[0],minc = 0;
for(var ci = 0; ci < cl; ci++){
if(temp > ca[ci]){
temp = ca[ci];
minc = ci;
}
}
return minc;
}, //获取页面的大小,从而调整列数。
widthchange:function(){ winWidth = document.body.clientWidth; //获取页面的宽度
//console.log("ttt "+document.documentElement.clientHeight);
var cols=Math.floor((winWidth-40)/this.imgWidth); //40是页面的两边的边距
//console.log(this.imgWidth);
var colsmar=Math.floor((winWidth-40-20*(cols+1))/this.imgWidth); //列数
//console.log(colsmar);
var cmargin=Math.floor(winWidth-this.imgWidth*colsmar-40)/(colsmar+1); //每一列的间距
//console.log(cmargin);
for(var i=0;i<colsmar;i++){
this.colHeight[i]=20;
this.colLeft[i]=(i+1)*cmargin+i*this.imgWidth;
}
},
//创建页面视图
createDiv:function(m){
var div="";
for(var n=0; n<m;n++){
var height=this.random(150,350);
div+="<div class='wf' style=height:"+height+"px;width:"+this.imgWidth+"px;><p>"+(n+1)+"</p><img src='img/loading.gif' data-src='img/"+(n+1)+".png' style=height:"+(height-45)+"px;width:"+this.imgWidth+"px;></div>";
}
this.id.innerHTML=div;
},
//设置每个小块的样式,边距等等
setStyle:function(){
for(var i=0;i<50;i++){
var lowcol=this.getMinCol(this.colHeight);
this.classname[i].style.left=this.colLeft[lowcol]+"px";
this.classname[i].style.top=this.colHeight[lowcol]+"px";
this.colHeight[lowcol]=this.classname[i].offsetHeight+this.classname[i].offsetTop+20;//offsetTop是数值
}
},
init:function(){
if(!this.flag){
//只创建小块一次,不然会每次都得重新加载图片
this.createDiv(50);
this.flag=1;//设置flag=1,这样下次就不会加载了
}
this.widthchange();
//newContainer.init(); this.setStyle(); }
} //只加载在可视区内的图片
function LazyLoad(id){
this.container=document.getElementById(id); //获取id
this.imgs=this.getImgs(); //得到img数组
this.init();
} LazyLoad.prototype={ init:function(){
this.update();
},
getImgs:function(){
var arr=[];
var imgs=this.container.getElementsByTagName("img");
for (var i=0,len=imgs.length;i<len;i++){
arr.push(imgs[i]);
}
return arr;
},
update:function(){
if(!this.imgs.length){
//console.log(this.imgs.length);
return;
}
var i=this.imgs.length;
for(--i;i>=0;i--){
if (this.show(i)){
this.imgs[i].src=this.imgs[i].dataset.src;
this.imgs.splice(i,1);
//console.log(newContainer.imgs[i].dataset.src);
}
}
},
//显示图片,判定图片是否在可是区域内。
show:function(i){
var img=this.imgs[i],
scrollTop=document.documentElement.scrollTop||document.body.scrollTop,
scrollBottom=scrollTop+document.documentElement.clientHeight,
imgTop=this.pageY(img),
imgBottom=imgTop+img.offsetHeight;
//如果满足,让他显示。
if(imgBottom>scrollTop && imgBottom<scrollBottom || (imgTop>scrollTop && imgTop<imgBottom))
return true;
return false;
},
//获取图片的最高点的y坐标
pageY:function(element){
if(element.offsetParent){
return element.offsetTop+this.pageY(element.offsetParent);
}else{
return element.offsetTop;
}
}
} //var dom=document.getElementById("container");
//var cName=document.getElementsByClassName("wf"); //绑定事件函数
function on(element,eventName,listener){
if (element.addEventListener){
element.addEventListener(eventName,listener,false);
}
else if (element.attachEvent){
element.attachEvent('on'+eventName,listener);
}
else
element['on'+eventName]=listener;
} var newWf=new wf({wth:300,id:"container",classname:"wf"});//创建瀑布流
var newContainer=new LazyLoad("container"); //惰性加载函数 on(window,"resize",function(){
newWf.init();
newContainer.update();
}) //绑定scroll事件
on(window,"scroll",function(){
newContainer.update();
}) </script>
</html>

js实现响应式瀑布流的更多相关文章

  1. 一款很实用的jQuery鼠标悬浮有动画效果的响应式瀑布流插件

    一款很实用的jQuery鼠标悬浮有动画效果的响应式瀑布流插件 在线预览 下载地址 实例代码 <!doctype html> <html lang="zh"> ...

  2. 响应式瀑布流插件Grid-A-Licious

    Grid-A-Licious是一款遵守MIT协议的响应式瀑布流插件.该插件总代码行不超过400行,实现很巧妙,使用时也很流畅.实现原理也很简单,根据屏幕宽度和参数中设置的列宽度以及每项之间的间隔宽度, ...

  3. jQuery超酷响应式瀑布流效果

    参考 http://www.sucaihuo.com/js/74.html <script src="scripts/blocksit.min.js"></scr ...

  4. Bootstrap 响应式瀑布流 (使用wookmark)

    使用瀑布布局 官方 http://www.wookmark.com/jquery-plugin GitHub https://github.com/GBKS/Wookmark-jQuery  (下载后 ...

  5. javascript适合移动端的响应式瀑布流插件实例演示

    在线预览 jQuery插件大全 实例代码 <div class="sucaihuo-container"> <div class="demo" ...

  6. Glide.js:响应式 & 触摸友好的 jQuery 滑块插件

    Glide.js 是一款响应式和对触摸友好的 jQuery 滑块.基于 CSS3 转换实现,并在低版本浏览器降级处理.Glide.js 简单,重量轻,快速,适用于智能手机,平板电脑和台式机.它支持 s ...

  7. 利用JS去做响应式布局

    利用JS去做响应式布局 js动态改变布局方式 // 取浏览器可视区高宽 var lw = $(window).width(); var lh = $(window).height();// 页面加载完 ...

  8. 用vue.js写的一个瀑布流的组件

    用vue.js写的一个瀑布流的组件:https://segmentfault.com/a/1190000010741319 https://www.jianshu.com/p/db3cadc03402

  9. js实现图片的瀑布流

    先看效果: 初始状态:

随机推荐

  1. nodeclub

    nodeclub笔记:https://cnodejs.org/topic/535601a20d7d0faf140303d8 先看一下框架,把没有接触过的部分熟悉一下. 熟悉一下package.json ...

  2. AngularJS controller as vm方式

    从AngularJS1.20开始引入了Controller as 新语法,以前版本在Controller 中必须注入$scope这个服务,才能在视图绑定中使用这些变量,$scope不是那么POJO(普 ...

  3. unigui验证微信服务器的有效性

    UNIGUI验证微信服务器的有效性: //////////////////////////////////////////// //UniGUIServerModuleHTTPCommand //公众 ...

  4. JavaScript中的工厂函数

    所谓工厂函数,就是指这些内建函数都是类对象,当你调用他们时,实际上是创建了一个类实例. 在学习jQuery的时候,我们经常会看到“工厂函数”这个概念,那么究竟什么是“工厂函数”呢?我们来看看概念,“所 ...

  5. node-webkit学习(2)基本结构和配置

    node-webkit学习(2)基本结构和配置 文/玄魂 目录 node webkit学习(2)基本结构和配置 前言 2.1  基本程序结构 2.2  package.json 2.2.1 必须的配置 ...

  6. Windows核心编程:第2章 字符和字符串处理

    Github https://github.com/gongluck/Windows-Core-Program.git //第2章 字符和字符串处理.cpp: 定义应用程序的入口点. // #incl ...

  7. ubuntu下sqlite命令

    介绍 Linux上的小巧的数据库,一个文件就是一个数据库. 安装Sqlite3 要安装 Sqlite3,可以在终端提示符后运行下列命令: sudo apt-get install sqlite3 检查 ...

  8. 面向对象总结、configparser配置文件模块、logging日志模块

    面向对象总结 # 学习态度# python基础 2个月# html css js jq 1个月 # 上课困 # 学习方法 :# 列出知识点# 例子 写了哪些 # 面向对象学了哪些块# 为什么要讲面向对 ...

  9. Java Calender 类详解

    一.   如何创建 Calendar 对象 Calendar 是一个抽象类, 无法通过直接实例化得到对象. 因此, Calendar 提供了一个方法 getInstance,来获得一个Calendar ...

  10. 【kuangbin专题】计算几何_半平面交

    1.poj3335 Rotating Scoreboard 传送:http://poj.org/problem?id=3335 题意:就是有个球场,球场的形状是个凸多边形,然后观众是坐在多边形的边上的 ...