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

思路分析

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

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

“获取成行元素集合中高度最低的那个元素,待放置的元素的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. jquery easyui tree异步加载子节点

    easyui中的树可以从标记中建立,也可以通过指定一个URL属性读取数据建立.如果想建立一棵异步树,需要为每个节点指定一个id属性值,这样在加载数据时会自动向后台传递id参数. <ul id=& ...

  2. IntelliJ IDEA 优化总结

    1.修改JVM参数 (IntelliJ IDEA 10.0.1包含以上版本不需要设置) 修改idea.exe.vmoptions配置文件调整以下内容:-Xms256m-Xmx384m-XX:MaxPe ...

  3. Javascript 创建对象的三种方法及比较【转载+整理】

    https://developer.mozilla.org/zh-CN/docs/JavaScript/Guide/Inheritance_and_the_prototype_chain 本文内容 引 ...

  4. 轻松python文本专题-字符与字符值转换

    场景: 将字符转换成ascii或者unicode编码 在转换过程中,注意使用ord和chr方法 >>> print(ord('a')) 97 >>> print(c ...

  5. 微信小程序 - 上传图片组件

    2019-01-08 更新至1.1:修复了一些问题 2019-03-14 全面更新,推荐:https://www.cnblogs.com/cisum/p/10533559.html 使用了es8的as ...

  6. Ubuntu Server无法安装busybox-initramfs

    解决方法很简单,使用英文安装就好,可以参考这个帖子:http://forum.ubuntu.com.cn/viewtopic.php?f=77&t=471547&p=3137632  

  7. 转:初探nginx架构(一)

    来源:http://tengine.taobao.org/book/chapter_02.html 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢? ...

  8. Android StageFrightMediaScanner源码解析

    1. 简单介绍 Android中在StageFrightMediaScanner实现对多媒体文件的处理. 此外在StageFrightMediaScanner定义了支持的多媒体文件类型. 文件位置 f ...

  9. Laravel返回不重复的某个字段信息列表

    ->groupBy('brand_id') ->pluck('brand_id');

  10. 20160210.CCPP体系具体解释(0020天)

    程序片段(01):01.二级指针.c 内容概要:二级指针 #include <stdio.h> #include <stdlib.h> //01.二级指针: // 1.使用场景 ...