瀑布流效果目前应用很广泛,像花瓣,新浪轻博,蘑菇街,美丽说等好多网站都有.也有好多支持该效果的前段框架,今天学习了一下这种效果的实现,不依赖插件,自己动手分析实现过程,为了便于叙述清楚,分析中的一些名词为自己拟定,不当之处还望见谅.

思路分析

步骤一:构建成行元素 + 寻找新增元素追加位置

瀑布流所有元素的宽度是固定的,我们用浏览器的宽度除以每个瀑布流块的宽度,就是每一行可容纳的瀑布流块的个数.因为,每个瀑布流块的高度不一,我们姑且把组成一行的这组元素称为成行元素,在成行元素放置完毕后,我们如果要再增加一个元素,那么它的位置应该这样找?

“获取成行元素集合中高度最低的那个元素,待放置的元素的top值应该是这个最低元素的高,left值应该是这个最低元素的left值”

这样,新增的这一个元素我们就找到了它存放的位置.这样成行元素中的最低高度值就变为了原来的高度+新增元素的高度.

步骤二:重复步骤一,依赖成行元素追加新元素

步骤一中我们已经实现了一次成行元素追加一个新的元素,这样新元素增加之后我们就构建了新的成行元素,之后的操作就是在新的成行元素中追加新元素,原理同步骤一.

步骤三:实现滚动位置监听,到底部时加载数据

代码实现

实现步骤一描述效果:

实现代码

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>瀑布流效果实现</title>
<script type="text/javascript" src="scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="scripts/jquery.easydrag.handler.beta2.js"></script>
<script type="text/javascript">
window.onload=function(){
//获取父级对象
var oParent = document.getElementById("main");
//获取父级[第一个参数]下的所有的子元素[按照第二个参数匹配]
var aPin = getClassObject(oParent,"pin");
//获取每一个块的宽度
var iPinW = aPin[0].offsetWidth;
// //计算每行放多少个pin(瀑布流块)页面的宽度/每一个瀑布流块的宽度
var num = Math.floor(document.documentElement.clientWidth/iPinW);
//重置父级的样式,这样保证图片整体居中
oParent.style.cssText="width:" + num*iPinW + "px;margin:0 auto;"; var compareArray = [];
//将一整行的瀑布流块的高度压入一个数组
for (var i = 0; i<num; i++) {
compareArray[i] = aPin[i].offsetHeight;
} //获取该行瀑布流高度最低的值
var minHeight = Math.min.apply('',compareArray);
//alert(compareArray + ",min=" + minHeight);
//获取改行高度值最小的瀑布流块的索引
var minHkey = getMinHeightKey(compareArray,minHeight); //为新增的瀑布流块增加样式
aPin[num].style.position = "absolute";
aPin[num].style.top = minHeight + "px";
//设定新增加的瀑布流块的top和left
aPin[num].style.left =aPin[minHkey].offsetLeft + "px"; //将该索引位置的高度改变为新增后的高度[原来瀑布流块的高度+新增的瀑布流块的高度]
compareArray[minHkey] += aPin[num].offsetHeight; }
/**
* 获取parent下所有样式名为className的对象集合
*/
function getClassObject(parent,className){
var obj = parent.getElementsByTagName("*");
var result = [];
for(var i=0; i<obj.length;i++){
//变量如果匹配className,将匹配的对象放入数组
if(obj[i].className==className){
result.push(obj[i]);
}
}
return result;
} /**
* 获取arr数组中值为minH的值在数组中的索引
*/
function getMinHeightKey(arr,minH){
for(key in arr){
if(arr[key] == minH){
return key;
}
}
}
</script>
<style type="text/css">
/*设置每一个瀑布流块*/
#main .pin{
width:220px;
height: auto;
padding: 15px 0px 0px 15px; /*上 右 下 左*/
float: left;
}
/*设置每一个瀑布流块中的图像样式*/
#main .pin .box{
width: 200px;
height: auto;
padding: 10px;
background: #FFF;
border: 1px solid #ccc;
box-shadow: 0px 0px 6px #ccc; /*中间投影*/
border-radius: 5px; /*圆角*/
}
#main .pin .box img{
width: 200px; }
</style>
</head>
<body>
<div id="main">
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012110120000859759.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072300483800466.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012101912011350194.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012102421195356552.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072312335411883.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012082910221472225.jpg">
</div>
</div> </div>
</body>
</html>

实现步骤二描述效果

实现代码

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>瀑布流效果实现</title>
<script type="text/javascript" src="scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="scripts/jquery.easydrag.handler.beta2.js"></script>
<script type="text/javascript">
window.onload=function(){
//获取父级对象
var oParent = document.getElementById("main");
//获取父级[第一个参数]下的所有的子元素[按照第二个参数匹配]
var aPin = getClassObject(oParent,"pin");
//获取每一个块的宽度
var iPinW = aPin[0].offsetWidth;
// //计算每行放多少个pin(瀑布流块)页面的宽度/每一个瀑布流块的宽度
var num = Math.floor(document.documentElement.clientWidth/iPinW);
//重置父级的样式,这样保证图片整体居中
oParent.style.cssText="width:" + num*iPinW + "px;margin:0 auto;"; var compareArray = [];
//遍历获取到的所有瀑布流块
for (var i = 0; i<aPin.length; i++) {
if(i<num){
//成行元素
compareArray[i] = aPin[i].offsetHeight;
}else{
//获取成行元素中高度最低的值
var minHeight = Math.min.apply('',compareArray);
//alert(compareArray + ",min=" + minHeight);
//获取成行元素中高度最低元素的索引
var minHkey = getMinHeightKey(compareArray,minHeight);
//为新增的瀑布流块设置定位
aPin[i].style.position = "absolute";
aPin[i].style.top = minHeight + "px";
//设定新增加的瀑布流块的top和left
aPin[i].style.left =aPin[minHkey].offsetLeft + "px";
//将该索引位置的高度改变为新增后的高度[原来瀑布流块的高度+新增的瀑布流块的高度]
compareArray[minHkey] += aPin[i].offsetHeight;
} } }
/**
* 获取parent下所有样式名为className的对象集合
*/
function getClassObject(parent,className){
var obj = parent.getElementsByTagName("*");
var result = [];
for(var i=0; i<obj.length;i++){
//变量如果匹配className,将匹配的对象放入数组
if(obj[i].className==className){
result.push(obj[i]);
}
}
return result;
} /**
* 获取arr数组中值为minH的值在数组中的索引
*/
function getMinHeightKey(arr,minH){
for(key in arr){
if(arr[key] == minH){
return key;
}
}
}
</script>
<style type="text/css">
/*设置每一个瀑布流块*/
#main .pin{
width:220px;
height: auto;
padding: 15px 0px 0px 15px; /*上 右 下 左*/
float: left;
}
/*设置每一个瀑布流块中的图像样式*/
#main .pin .box{
width: 200px;
height: auto;
padding: 10px;
background: #FFF;
border: 1px solid #ccc;
box-shadow: 0px 0px 6px #ccc; /*中间投影*/
border-radius: 5px; /*圆角*/
}
#main .pin .box img{
width: 200px; }
</style>
</head>
<body>
<div id="main">
<!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012110120000859759.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072300483800466.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012101912011350194.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012102421195356552.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012072312335411883.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012082910221472225.jpg">
</div>
</div> <!--每一个小块-->
<div class="pin">
<div class="box">
<img src="data:images/2012082910024626515.jpg">
</div>
</div> </div>
</body>
</html>

会看到新增的瀑布流块在新的成行元素中自动寻找高度最低的那个元素块的相对位置进行追加.添加更多元素查看效果

步骤三:实现滚动到底部时加载数据
该部分没有什么功能,只是检测滚动条的位置距离浏览器底部的相对距离进行数据加载,加载数据时创建对应的瀑布流块.判断相对距离的实现逻辑如下

        function checkScrollSite(){
var oParent = document.getElementById("main"); var aPin = getClassObject(oParent,"pin");
//加载数据依赖最后一个瀑布流块变化
var lastPinHeight = aPin[aPin.length-1].offsetTop + Math.floor(aPin[aPin.length-1].offsetHeight/2) ;
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
//浏览器高度
var documentH = document.documentElement.clientHeight; if(lastPinHeight<documentH + scrollTop){
//请求数据
return true;
}
return false;
}

在此感谢,郑印在学习上给予的指导.

转载请注明出处:[http://www.cnblogs.com/dennisit/p/3244987.html]

web前端学习笔记-瀑布流的算法分析与代码实现的更多相关文章

  1. 【前端】Web前端学习笔记【1】

    ... [2015.12.02-2016.02.22]期间的学习笔记. 相关博客: Web前端学习笔记[2] 1. JS中的: (1)continue 语句 (带有或不带标签引用)只能用在循环中. ( ...

  2. web前端学习笔记

    web前端学习笔记(CSS盒子的定位) 相对定位 使用相对定位的盒子的位置常以标准流的排版方式为基础,然后使盒子相对于它在原本的标准位置偏移指定的距离.相对定位的盒子仍在标准流中,它后面的盒子仍以标准 ...

  3. 【前端】Web前端学习笔记【2】

    [2016.02.22至今]的学习笔记. 相关博客: Web前端学习笔记[1] 1. this在 JavaScript 中主要有以下五种使用场景 在全局函数调用中,this 绑定全局对象,浏览器环境全 ...

  4. Web前端学习笔记(001)

    ....编号    ........类别    ............条目  ................明细....................时间 一.Web前端学习笔记         ...

  5. web前端学习笔记:文本属性

    今天的web前端笔记主要讲述文本属性,希望能帮助到正在学习web前端开发的初学者们,废话不多说了,一起来看看文本属性的相关内容吧. 文本属性 文本缩进 将Web页面上的一个段落第一行缩进,这是一种最常 ...

  6. Web前端学习笔记:Bootstrap框架

    很久之前就有很多人给我推荐twitter的Bootstrap框架,但是直到前几天我才真正学习了下Bootstrap,的确是相当棒的框架,至少从视觉体验上超越了很多以前碰到了前端UI框架.今天我要聊聊B ...

  7. web前端学习笔记(二)---Django

    [前言]前面(一)学习了web的基础知识,介绍到了MVC,项目使用一个Django框架. Django book:https://code.ziqiangxuetang.com/django/djan ...

  8. Web前端学习笔记之jQuery基础

    0x0 jQuery介绍 jQuery是一个轻量级的.兼容多浏览器的JavaScript库. jQuery使用户能够更方便地处理HTML Document.Events.实现动画效果.方便地进行Aja ...

  9. Web前端学习笔记之BootStrap

    Bootstrap介绍 Bootstrap是Twitter开源的基于HTML.CSS.JavaScript的前端框架. 它是为实现快速开发Web应用程序而设计的一套前端工具包. 它支持响应式布局,并且 ...

随机推荐

  1. (纪录片)光的故事 BBC Light Fantastic (2004)

    简介: 导演: Jeremy Turner主演: Simon Schaffer / Dimitri Andreas ... Al Hazen / Edmund Dehn ... Priest/Old ...

  2. NSobject 结构

    参考地址:  https://iosdevelopmenttutorials.wordpress.com/tag/uiscrollview/ Apple Documentation

  3. 微软BI 之SSRS 系列 - 如何实现报表导航 Navigation 和钻取 Drill Down 的效果

    开篇介绍 如何在 SSRS 报表中实现标签导航 Navigation 和向下钻取 Drill Down的效果? 如同下面这个例子一样 - 在页面第一次加载的时候,默认显示是全部地区的销售总和情况,上面 ...

  4. leverage准确翻译,译法,英文

    这个词的翻译很有问题.很多大词典都只有这么几个译法:影响力,杠杆.作为动词的时候我建议翻译为:借助,凭借,凭仗,依仗,借重某外文原稿(https://www.vmware.com/files/pdf/ ...

  5. TQ2440触摸屏

    s3c2440集成了4线制电阻式的触摸屏接口,触点坐标的检测是通过A/D转换来实现的. s3c2440一共有4种触摸屏接口模式: (1)等待中断模式 设置ADCTSC寄存器为0xD3即可令触摸屏控制器 ...

  6. SSH使用Log4j

    1. 将Jar文件log4j-1.2.14.jar导入项目. 2. 在src文件夹下新建log4j.properties文件: log4j.rootLogger = debug,stdout,D,E ...

  7. 深入理解JVM内存区域与内存分配

    前言:这是一篇关于JVM内存区域的文章,由网上一些有关这方面的文章和<深入理解Java虚拟机>整理而来,所以会有些类同的地方,也不能保证我自己写的比其他网上的和书本上的要好,也不可能会这样 ...

  8. Mule 入门之:环境搭建

    Mule 入门之:环境搭建 JDK1.5或以上版本Eclipse3.3以上 下载与安装:目前最新版本为2.2.1 下载,下载后得到一名为mule-standalone-2.2.1.zip的压缩文件,解 ...

  9. 一个简单的 JSON 生成/解析库

    这是一个单文件的,适用于C语言的, JSON 读写库. 先说明,不想造轮子,代码是从这里拿来的: https://www.codeproject.com/Articles/887604/jWrite- ...

  10. electron vue 开发客户端程序

    文档知识点 https://electronjs.org/docs/tutorial/about (1)Electron通过将Chromium和Node.js合并到同一个运行时环境中,并将其打包为Ma ...