案例 - 瀑布流效果学习笔记及源码整理(浮动式瀑布流)
author:702004176@qq.com
time:2017-04-13
description:瀑布流学习与制作
1:瀑布流的特点
(1)宽度相同,高度不相同。或者 高度相同宽度不相同
(2)可以一直下拉加载(无止境)
2:瀑布流两种常见的形式
(1)浮动式 - 即外层容器浮动布局(简单)
(2)定位式 - 没有单独的浮动容器,而是按照外层容器进行一一定位(复杂点)
此篇详解浮动式:
原理:
1.外层容器左浮动
2.判断哪一个容器为最小容器(当垂直瀑布时,最短的为最小的。当水平排列接龙时,宽度最窄的为最小的)
3.将图片(内容)插入到最小容器内。
判断,当滚动条滚动到一定程度,循环执行2和3
【其实原理这一点,说白了就是可以想象成三队人在排队等地铁,后边来的人肯定是自动往队伍最短的那一列的最后接着排,
没有人会在早高峰的地铁站,站最长的那一队后边吧。这就是赋予机器人类的智慧啊。学会择优、择木而栖】
那么问题来了,怎么判断谁最短?程序又不长眼睛不会看出来,只有经过数字化的计算和判断:
代码要点:
1.创建元素 document.createElement(“元素”);
2.获得屏幕的宽和高,如果不做横向的瀑布流,获得高就行了。
document.documentElement.clientHeight;(浏览器显示出来的高度)
3.触发滚动条事件 window.onscroll
4.获得滚动条向下滚动的高度、距离
document.documentElement.scrollTop ||
document.body.scrollTop,(||是为了处理兼容问题做的“或”双选一);
5.滚动后body高度,整个内容区域的高度
document.body.scrollHeight
反正我一开始是晕了~搞不懂这scrollTop、clientHeight、scrollHeight~~~
下图是我理解了这三个属性的原理后自己画的效果图+注释。
这个结论在最后的代码中,经过测试是合拍的。
2017-04-17 10:43:19
关于这群top的详细解说在博客园另一个博主那里非常详细,传送带:http://www.cnblogs.com/yuteng/articles/1894578.html
实验证明:
物体的clientHeight:可视区域的长度值:就是所有内容叠加在一起的高度,在没有滚动条的情况下,且没有padding和border也没有box-sizing的设置情况下,和高度一样。
当然是在可见的情况下,那么visibility: hidden;也是可以被计算的,只要不是display:none;这种情况下,他还是在文档流中的。
不包括margin但是包括padding(在没有box-sizing的情况下)
当加了box-sizing这个概念后,就会不包括padding的高度。只有纯净的高度值。(其实严格来说,加了box-sizing后,他的高度就包含padding了,所以说,和本来的高度值是一样的。看上去就像不包括paddng一样,其实padding在高度中,而高度值已变成原来的高度减去上下padding了。)
当然,不管省么情况下,border的宽高的都是和padding处理方式差不多。只不过在没有box-sizing的时候,只计算内容和padding的和,不计算border的。除非box-sizing是border-box她才计算border。
但是和scrolltop没有什么区别
top和left是从margin宽度内部开始计算的
2017-04-24 11:00:19
以上划线结论只是在我不明不白情况下做的很不全面的测试时,所写的某一种特定情况下的现象描述,有待再次求证。
经过我后来的学习,真正搞明白三者的关系和各自的具体含义和作用,总结在此篇文章:http://www.cnblogs.com/padding1015/p/6737363.html
2017-04-18 09:43:55
昨天研究很久,虽然理论上知道了各种top的区别,但是还是晕晕乎乎不知道用到哪里。结果下班路上一听视频就全部都明白了。要不说看书背理论没用呢!还是得实战,自己的认识才是最深刻的。
开始上手写就会有千奇百怪的问题出现。首先逻辑错误的就算了,改正或想通了就好。浏览器的处理问题就烦了:
火狐和谷歌遍历出来的顺序不一样啊。我程序上的思路是,图片按照哪个ul高度短往哪个ul中流动的顺序来,但是两个浏览器就是两种效果
而几张图片的顺序是这样的:
很明显,从第四张图片开始,谷歌就随心所欲了。
火狐是按照咱们设想的那样,谁短去谁那里,但是谷歌就是任性的0,1,2的来。(如图,是图片依次插入时,ul的索引值)
火狐: 谷歌:
问题很明显。
通过下面这段代码的 alert 测试。
我发现:谷歌是遍历三个ul,不传图,直接再次弹出第一个ul的高度,然后第二个、第三个、直到三次都弹出来,
且不传图第二次遍历,这个的时候,第一个ul的高度会变成21,后两个是0;
不传图第三次遍历,这时,第一个、第二个ul的高度会变成21,最后那个ul高度是0;
不传图第四次遍历,这时,三个高度均为21px;
不传图第五次遍历,第一个高度为21+21=42px;第二三个依旧21px;
按此规律重复下去,每当三个ul高度一致时,三个ul高度依次再加21;
然后,最后的最后,遍历完毕,一次性传入设定的n张图片/内容。
遍历数值和规律如下图:
问题的关键在于不传图和offset的计算上,既然不传图,21px的值又来自何方?
再看火狐,他是先遍历三个ul并分别弹一次ul的高度,最后在这三个ul中计算出最短的,传一张图,然后重复上述遍历步骤,并依次传规定张数。
下图是火狐遍历三个ul重复19次后得到的遍历规律和每次计算得出ul的offsetHeight的值的部分,
可以看出,第一行三个0表示第一遍遍历三个ul均为空,就将第一张图片插入第一个ul中,
然后,第二次遍历,第一个ul的高度就是392——第一张图的高度。
而另外两个ul依旧为0,这时将第二张图片插入第二个ul中。
第三遍遍历时,第一二个ul已经有了图片,高度也就是392和415,而第三个没有图,所以第三个依旧为0;这时第三张图片被放进第三个ul中。
第四遍遍历时,三个ul都有了图片且高度不一致,程序就按照我们原来的设定,三个都计算出来并比较,得到最短的穿进去,最后有了我们看到的效果。
这就是导致他们最后传入图片顺序不一致的最终原因吧。看老师的演示效果,在谷歌中也是同样的问题。
四种浏览器对 clientHeight、offsetHeight、scrollHeight、clientWidth、offsetWidth 和 scrollWidth 的解释差异http://blog.csdn.net/tammy_zhu/article/details/7406073
经过测试也很明显可以看出,
火狐和谷歌对于ul的offsetHeight的计算数值是不一样的,火狐是2755px,谷歌是147px
但是经过我对offset偏移值进行特别测试的页面中,谷歌和火狐弹出的偏移值和客户区大小的值在各种情况下都是一样的。
另body.clientHeight在谷歌和火狐中也是不一样的解释,谷歌972,火狐947、
当然,clientHeight表示的是可视区域的高度,也就是浏览器内容区域的高度,
这要在同一台电脑屏幕高度的基础上减去每个浏览器标签栏和地址栏的高度,而每个浏览器的标签栏和地址栏的高度又不一样。。。
所以不一样也正常,但是不会差太多一般。
说了这么多废话,还是上最终代码吧,我封装好的js库,可以实现多次调用了。
html代码
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>瀑布流</title> 6 <meta name="author" content="郭菊锋-xing.org1^" /> 7 <meta name="Description" content="浮动式瀑布流效果"/> 8 <style type="text/css"> 9 *{margin: 0;padding: 0;list-style: none;} 10 .fdpbl{width: 720px;margin: 30px auto;*zoom:1;} 11 .fdpbl:after{clear: both;content: "";display: block;} 12 .fdpbl ul{float: left;width: 230px;overflow: hidden;margin-right: 10px;} 13 .fdpbl li{width: 230px;margin-top: 8px;box-shadow: 1px 3px 2px 1px #ddd;} 14 .fdpbl li img{width: 100%;} 15 </style> 16 </head> 17 18 <body> 19 <div class="fdpbl" id="fdpbl"> 20 <ul></ul> 21 <ul></ul> 22 <ul></ul> 23 </div> 24 <script src="这里调用封装好的js代码.js"></script> 25 <script type="text/javascript"> 26 window.onload = function(){ 27 pbl({ 28 Box: "fdpbl", 29 Ul: "ul", 30 Url: "src='../img/", 31 num: "19", 32 }); 33 } 34 </script> 35 </body> 36 37 </html>
js代码:
1 function pbl(oJson) { 2 var oDiv = document.getElementById(oJson.Box); 3 var oUl = oDiv.getElementsByTagName(oJson.Ul); 4 var nNum = oJson.num; 5 var sUrl = oJson.Url; 6 createImg(); 7 //滚动持续加载 8 window.onscroll = function() { 9 var sT = document.documentElement.scrollTop || document.body.scrollTop; 10 var vH = document.documentElement.clientHeight; 11 var bH = document.body.scrollHeight * 0.9; 12 if(sT + vH > bH) { 13 createImg(); 14 } 15 }; 16 //判断ul的高度谁最短,然后返回索引值 17 function ulIndex(oUl) { 18 var oldHeight = 1000000000; 19 var index = 0 20 for(var i = 0; i < oUl.length; i++) { 21 var nowHeight = oUl[i].offsetHeight; 22 if(nowHeight <= oldHeight) { 23 oldHeight = nowHeight; 24 index = i; 25 } 26 } 27 return index; 28 }; 29 //第一版本的创建——createImg函数; 30 function createImg() { 31 var src = null; 32 for(var a = 1; a <= nNum; a++) { 33 src = "<li><img "+ sUrl + a + ".jpg' alt=''/></li>" 34 var index = ulIndex(oUl); 35 oUl[index].innerHTML += src; 36 } 37 }; 38 }
特别说明:参数中url和num是不必要的,我是为了想,万一图片的路径和想要显示的数量不同就还得再次深入封装。这样,一劳永逸吧。
压缩版js
;function pbl(oJson){var oDiv=document.getElementById(oJson.Box);var oUl=oDiv.getElementsByTagName(oJson.Ul);var nNum=oJson.num;var sUrl=oJson.Url;createImg();window.onscroll=function(){var sT=document.documentElement.scrollTop||document.body.scrollTop;var vH=document.documentElement.clientHeight;var bH=document.body.scrollHeight*0.9;if(sT+vH>bH){createImg()}};function ulIndex(oUl){var oldHeight=1000000000;var index=0;for(var i=0;i<oUl.length;i+=1){var nowHeight=oUl[i].offsetHeight;if(nowHeight<=oldHeight){oldHeight=nowHeight;index=i}}return index};function createImg(){var src=null;for(var a=1;a<=nNum;a+=1){src="<li><img "+sUrl+a+".jpg' alt=''/></li>";var index=ulIndex(oUl);oUl[index].innerHTML+=src}}};
JQ处理版
HTML:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>浮动瀑布流之JQ方法处理</title> 6 <meta name="Description" content="pblOfFloat-jq.js"/> 7 <style type="text/css"> 8 *{margin: 0;padding: 0;list-style: none;} 9 #jqpbl{width: 960px;margin: 0 auto;*zoom: 1;} 10 #jqpbl:after{content: "";clear: both;display: block;} 11 #jqpbl ul{width: 230px;float: left;margin-right: 10px;} 12 #jqpbl li{width: 230px; margin-top: 10px; -webkit-box-shadow: 1px 3px 3px 3px #DDDDDD;box-shadow: 1px 3px 3px 3px #ddd;} 13 #jqpbl img{width: 100%;vertical-align: bottom;} 14 </style> 15 </head> 16 <body> 17 <div id="jqpbl"> 18 <ul></ul> 19 <ul></ul> 20 <ul></ul> 21 </div> 22 </body> 23 </html> 24 <script src="../js/jquery-1.8.3.min.js" type="text/javascript" charset="utf-8"></script> 25 <script src="pblOfFloat-jq.min.js" type="text/javascript" charset="utf-8"></script> 26 <script type="text/javascript"> 27 $(document).ready(function(){ 28 pblOfFloatJQ("#jqpbl ul") 29 }); 30 </script>
pblOfFloat-jq.min.js
1 //浮动瀑布流jq写法 2 function pblOfFloatJQ(oUl){var oUl=$(oUl);appendImg();$(window).scroll(function(){var sT=document.documentElement.scrollTop||document.body.scrollTop;var cH=document.documentElement.clientHeight;var bH=document.body.scrollHeight*.8;if(sT+cH>=bH){appendImg()}});function appendImg(){var str=null;for(var n=1;n<20;n+=1){str='<li><img src="../img/'+n+'.jpg" alt="第'+n+'张"/></li>';var index=compare();oUl[index].innerHTML+=str}};function compare(){var oldHeight=23333333333;var index=0;for(var i=0;i<oUl.length;i+=1){var newHeight=oUl[i].offsetHeight;if(newHeight<oldHeight){oldHeight=newHeight;index=i}}return index}}
代码解析:
function pbl(oJson) {
//传入参数,获取必要数据以备使用。
var oDiv = document.getElementById(oJson.Box);
var oUl = oDiv.getElementsByTagName(oJson.Ul);
var nNum = oJson.num;
var sUrl = oJson.Url;
//在滚动之前先加载一次,防止空白页面。
createImg();
//滚动持续加载,onscroll来触发页面的滚动事件
window.onscroll = function() {
//准备参数
var sT = document.documentElement.scrollTop || document.body.scrollTop;
var vH = document.documentElement.clientHeight;
var bH = document.body.scrollHeight * 0.9;
/*
* sT:滚动条滚动的高度
* vH:浏览器窗口的高度
* bH:总的内容高度,所有文本组起来撑开body的总高度.乘以0.9表示获得高度的90%的值
* sT + vH == bH 就表示,滚动条已经滚到底部了。大于就表示滚超过了,
* 大于90%,想让滚动条还没到底的时候就加载,让效果更流畅。
*/
//做判断,监听滚轮的位置,
if(sT + vH > bH) {
createImg();
//当其将要打过html高度的90%时,再次加载插入img的函数。
}
};
//下边:ulIndex函数,判断ul的高度谁最短,然后返回索引值
/*
* 传参,传进来之前准备好的几个ul集合。
* 思考:这里不传参就不能用准备好的ul集合?
* 涉及函数的作用域:http://www.jb51.net/article/43068.htm
* 函数内的变量无法在函数外面访问,在函数内却可以访问函数外的变量。所以这里不用传参
* js作用域链的变量访问规则是:如果当前作用域内存在要访问的变量,则使用当前作用域的变量,否则到上一层作用域内寻找,直到全局作用域,如果找不到,则该变量为未声明。
*/
function ulIndex(oUl) {
var oldHeight = 1000000000;
//设定一个很大很大的高度值,让页面在一开始加载的时候,作比较用,目的上让随便一个ul都小于他,这样后边的if就会成立
var index = 0
//初始化index值
for(var i = 0; i < oUl.length; i++) {
//在现有的几个ul集合中遍历,循环。
var nowHeight = oUl[i].offsetHeight;
alert(nowHeight)
if(nowHeight <= oldHeight) {
//通过赋值,来达到比较几个集合的目的
oldHeight = nowHeight;
//获取到这个ul的下标赋给index
index = i;
}
}
return index;
//返回这个ul的索引值
};
//createImg函数:一个完整版本的创建
function createImg() {
var src = null;
//小于等于19的话,一次性就会加载19张
for(var a = 1; a <= nNum; a++) {
//创建li和img结构,并将图片序号设为动态
src = "<li><img "+ sUrl + a + ".jpg' alt=''/></li>"
//这里再次取得传过来的符合条件的ul下标,
/*
* 这个处理方法很巧妙。因为ul的循环次数和图片的插入不同,应该是两个步骤。
* 而通过回调函数传参的方法把ul遍历计算出来的符合条件的下标传进这个函数中,
* 利用了另一个函数return和这个函数调用获得结果这一思想。很巧妙地化解了碰撞的难题。
*/
var index = ulIndex(oUl);
//最后把当前的图片加入到符合条件的ul中。
oUl[index].innerHTML += src;
}
};
}
拓展
利用上面window.onscroll事件函数中的代码(为了测试,代码稍有更改),经过一番测试来证明注释图中的结论:
var sT = document.documentElement.scrollTop || document.body.scrollTop;
var vH = document.documentElement.clientHeight;
var bHq = document.body.scrollHeight;
if(sT + vH == bHq) {
console.log(sT + vH);
console.log(bHq)
createImg();
}
控制台输出的结果如下图:
判断得知,documentElement.scrollTop || document.body.scrollTop + documentElement.clientheight === body.scrollHeight的值