搜索

查看: 402|回复: 1

Javascript 瀑布流实现的两种方式:固定列数的浮动布局与绝对定位自适应宽度

[复制链接]

476

主题

0

好友

1709

积分

管理员

发表于 2012-11-10 19:34:27 |显示全部楼层
瀑布流已经火了一段时间了,自己最近才有空研究一下,网上关于瀑布流的帖子也很多,网上一般是说三种方式,固定列数的浮动布局,CSS3列布局,绝对定位布局
推荐两个关于瀑布流的帖子,写得比我详细多了:
http://www.w3cvip.com/thread-423-1-1.html    张鑫旭的   {我本地化了}
这里主要是记录一下我的实现方式,用数组模拟的数据,也可以用AJAX实现读取数据,底部提供DEMO代码下载!
一、固定列数的浮动布局
  这种方式简单适用,先按照列数把布局固定好,然后在滚动事件中分别在每一列插入相应的数据既可,代码比较简单就直接折叠了:
  其实就一个滚动加载事件。我这里没有做按高低排序。
     代码如下:  
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset=”utf-8″>
  5. <title>瀑布流布局(基于固定宽度的浮动定位)</title>
  6. <link rel=”stylesheet” href=”style/style.css”>
  7. </head>
  8. <body>
  9. <div id=”warp” class=”warp”>
  10. <div class=”full” id=”row1″>
  11. <div class=”water”>
  12. <a href=”javascript:void(0)”><img src=”images/01.JPG” alt=”"></a>
  13. <p class=”title”>瀑布流布局</p>
  14. </div>
  15. <div class=”water”>
  16. <img src=”images/02.JPG” alt=”">
  17. <p class=”title”>瀑布流布局</p>
  18. </div>
  19. <div class=”water”>
  20. <img src=”images/09.JPG” alt=”">
  21. <p class=”title”>瀑布流布局</p>
  22. </div>
  23. <div class=”water”>
  24. <img src=”images/15.JPG” alt=”">
  25. <p class=”title”>瀑布流布局</p>
  26. </div>
  27. </div>
  28. <div class=”full” id=”row2″>
  29. <div class=”water”>
  30. <img src=”images/03.jpg” alt=”">
  31. <p class=”title”>瀑布流布局</p>
  32. </div>
  33. <div class=”water”>
  34. <img src=”images/04.JPG” alt=”">
  35. <p class=”title”>瀑布流布局</p>
  36. </div>
  37. <div class=”water”>
  38. <img src=”images/10.JPG” alt=”">
  39. <p class=”title”>瀑布流布局</p>
  40. </div>
  41. <div class=”water”>
  42. <img src=”images/08.JPG” alt=”">
  43. <p class=”title”>瀑布流布局</p>
  44. </div>
  45. </div>
  46. <div class=”full” id=”row3″>
  47. <div class=”water”>
  48. <img src=”images/05.JPG” alt=”">
  49. <p class=”title”>瀑布流布局</p>
  50. </div>
  51. <div class=”water”>
  52. <img src=”images/06.JPG” alt=”">
  53. <p class=”title”>瀑布流布局</p>
  54. </div>
  55. <div class=”water”>
  56. <img src=”images/11.JPG” alt=”">
  57. <p class=”title”>瀑布流布局</p>
  58. </div>
  59. <div class=”water”>
  60. <img src=”images/14.JPG” alt=”">
  61. <p class=”title”>瀑布流布局</p>
  62. </div>
  63. </div>
  64. <div class=”full last” id=”row4″>
  65. <div class=”water”>
  66. <img src=”images/07.JPG” alt=”">
  67. <p class=”title”>瀑布流布局</p>
  68. </div>
  69. <div class=”water”>
  70. <img src=”images/08.JPG” alt=”">
  71. <p class=”title”>瀑布流布局</p>
  72. </div>
  73. <div class=”water”>
  74. <img src=”images/12.JPG” alt=”">
  75. <p class=”title”>瀑布流布局</p>
  76. </div>
  77. <div class=”water”>
  78. <img src=”images/13.JPG” alt=”">
  79. <p class=”title”>瀑布流布局</p>
  80. </div>
  81. </div>
  82. </div>
  83. <script type=”text/javascript” src=”style/waterfull.js”></script>
  84. </body>
  85. </html>
复制代码
  JS代码:  
  1. /* *
  2. * 基于固定宽度的浮动定位的瀑布流
  3. * 实现简单,其实就是一个滚动加载数据而已
  4. * 缺点布局不随宽度的变化而改变,如果有图片特别长的时候,最高的列与最低的列有可能差距大,空白大
  5. * by VVG <a href="http://www.cnblogs.com/NNUF/" target="_blank">http://www.cnblogs.com/NNUF/</a>
  6. */
  7. var WaterFull = {
  8. $:function(id){return document.getElementById(id);},
  9. // 每次滚动需要加载的数据,可以用ajax替代读取,每次分批加载
  10. data:[{imgUrl:'images/01.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位01'},
  11. {imgUrl:'images/02.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位02'},
  12. {imgUrl:'images/03.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位03'},
  13. {imgUrl:'images/05.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位04'},
  14. {imgUrl:'images/06.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位05'},
  15. {imgUrl:'images/07.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位06'},
  16. {imgUrl:'images/08.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位07'},
  17. {imgUrl:'images/09.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位08'},
  18. {imgUrl:'images/10.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位09'},
  19. {imgUrl:'images/11.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位10'},
  20. {imgUrl:'images/12.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位11'},
  21. {imgUrl:'images/13.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位12'},
  22. {imgUrl:'images/14.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位13'},
  23. {imgUrl:'images/15.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位14'}
  24. ],
  25. createChild:function(link,imagesUrl,title){
  26. var str = ‘<a href=”‘ + link + ‘”><img src=”‘ + imagesUrl + ‘”></a>’ + ‘<p class=”title”>’ + title + ‘</p>’;
  27. var div = document.createElement(‘div’);
  28. div.className = ‘water’;
  29. div.innerHTML = str;
  30. return div;
  31. },
  32. //绑定事件
  33. on:function(element, type, func) {
  34. if (element.addEventListener) {
  35. element.addEventListener(type, func, false); //false 表示冒泡
  36. } else if (element.attachEvent) {
  37. element.attachEvent(‘on’ + type, func);
  38. } else {
  39. element['on' + type] = func;
  40. }
  41. },
  42. //获取列高度,返回数组,从小到大排序
  43. getRowByHeight:function(){
  44. var row = [this.$('row1'),this.$('row2'),this.$('row3'),this.$('row4')];
  45. var height = [];
  46. for(var i = 0;row<i>;i++){
  47. row<i>.height = row<i>.offsetHeight;
  48. height.push(row<i>);
  49. }
  50. // 对高度进行排序,低–》高,保证最矮的优先加载
  51. height.sort(function(a,b){
  52. return a.height - b.height;
  53. });
  54. return height;
  55. },
  56. //获取页面总高度(总高度 = 卷去高度 + 可视区域高度)
  57. getPageHeight:function(){
  58. return document.documentElement.scrollHeight || document.body.scrollHeight ;
  59. },
  60. // 获取页面卷去的高度
  61. getScrollTop:function(){
  62. return document.documentElement.scrollTop || document.body.scrollTop;
  63. },
  64. // 获取页面可视区域宽度
  65. getClientHeigth:function(){
  66. return document.documentElement.clientHeight || document.body.clientHeight;
  67. },
  68. append:function(){
  69. var i = 0,rows = this.getRowByHeight(),div,k;
  70. for(;this.data<i>;i++){
  71. div = this.createChild(this.data<i>.link, this.data<i>.imgUrl,this.data<i>.title);
  72. // 因为是4列,所以数据以4列一个轮回加载
  73. k = ((i+1)>4)?i%4:i;
  74. // 在列上添加数据
  75. rows[k].appendChild(div);
  76. }
  77. },
  78. onScroll:function(){
  79. // 获取高度等数据
  80. var height = WaterFull.getPageHeight();
  81. var scrollTop = WaterFull.getScrollTop();
  82. var clientHeight = WaterFull.getClientHeigth();
  83. // 如果滚动到最底部,就加载
  84. if(scrollTop + clientHeight > height – 50){
  85. WaterFull.append();
  86. }
  87. },
  88. timer:null
  89. };
  90. WaterFull.on(window, ‘scroll’,function(){
  91. clearTimeout( WaterFull.timer ); //清除上一次,性能优化
  92. WaterFull.timer = setTimeout(WaterFull.onScroll,500);
  93. });</i></i></i></i></i></i></i></i>
复制代码

二、绝对定位实现的瀑布流,宽度自适应,resize重排
  绝对定位实现方式因为要获取每格的高度,然后根据高度来计算定位位置,所以必须要知道图片的高度,如果没有高度,定位就不准确,所以传递数据的时候需要图片的高度。
  我是这样计算绝对定位的位置的,left根据列数来,这个略过,下面主要讲TOP值的获取:
  比如如下的排列方式,数字代表格子
  0    1     2     3    4     5
      6    7    8    9     10   11
     12   13  14   15   16   17
    第12格子的绝对定位TOP值 =  第0格的高度(offsetHeight) + 相隔距离(margin) + 6格的高度(offsetHeight) + 相隔距离(margin);
这个计算就通过一个循环来实现:
  计算定位的代码如下:     
  1. function sort(){
  2. var num = getColumnNum(), left, top, column;
  3. //nowNum的作用是不让已经加载的数据重新计算定位排列
  4. for (var j = nowNum, k = cells.length; j < k; j++, nowNum++) {
  5. // 初始化top的值
  6. top = 0;
  7. // 获取当前为第几列
  8. column = j < num ? j : j % num;
  9. // 计算可以得到当前列的LEFT值
  10. left = column * (cellClientWidth + columnMarginRight);
  11. cells[j].style.left = left + ‘px’;
  12. if (j < num) {
  13. // 第一列top值为0
  14. cells[j].style.top = ’0px’;
  15. } else {
  16. // 计算TOP值,等于当前格子的顶上每列的高度相加
  17. for (var m = column; m < j; m = m + num) {
  18. top = top + cells[m].offsetHeight + columnMarginRight;
  19. }
  20. cells[j].style.top = top + ‘px’;
  21. }
  22. }
  23. }
复制代码

瀑布流绝对定位总代码如下:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset=”utf-8″>
  5. <title>瀑布流布局(绝对定位)</title>
  6. <style type=”text/css”>
  7. html, body{
  8. height:100%
  9. }<p style="margin-bottom: 14px;"></p><p style="margin-bottom: 14px;">html, body, #warp p{
  10. margin:0;
  11. padding:0
  12. }</p><p style="margin-bottom: 14px;">#warp{
  13. margin:20px auto;
  14. position:relative;
  15. min-height:1000px;
  16. }</p><p style="margin-bottom: 14px;">#warp .cell{
  17. padding:10px;
  18. border:1px solid #ccc;
  19. box-shadow:2px 2px 5px #ccc;
  20. overflow:hidden;
  21. }</p><p style="margin-bottom: 14px;">#warp .cell a{
  22. text-decoration:none;
  23. color:#878787;
  24. font:14px/1.5em Microsoft YaHei;
  25. }
  26. img{ border:none; }
  27. </style>
  28. </head>
  29. <body>
  30. <div id=”warp” class=”warp clearfix”></div>
  31. <script type=”text/javascript”>
  32. var data = [
  33. {imgUrl:'images/01.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位01', height:273},
  34. {imgUrl:'images/02.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位02', height:144},
  35. {imgUrl:'images/03.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位03', height:168},
  36. {imgUrl:'images/04.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位04', height:275},
  37. {imgUrl:'images/05.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位05', height:288},
  38. {imgUrl:'images/06.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位05', height:272},
  39. {imgUrl:'images/07.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位06', height:285},
  40. {imgUrl:'images/08.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位07', height:282},
  41. {imgUrl:'images/09.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位08', height:190},
  42. {imgUrl:'images/10.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位09', height:236},
  43. {imgUrl:'images/11.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位10', height:225},
  44. {imgUrl:'images/12.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位11', height:264},
  45. {imgUrl:'images/13.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位12', height:144},
  46. {imgUrl:'images/14.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位13', height:192},
  47. {imgUrl:'images/15.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位14', height:343}
  48. ];
  49. var waterFull = function (options) {
  50. var id = options.id,
  51. picWidth = options.picWidth || 190,
  52. columnPadding = options.columnPadding || 10,
  53. columnBorder = options.columnBorder || 1,
  54. columnMarginRight = options.columnMargin || 20,
  55. // 格子总宽度
  56. cellClientWidth = picWidth + columnPadding * 2 + columnBorder * 2,
  57. obody = document.getElementsByTagName(‘body’)[0],
  58. owarp = document.getElementById(id),
  59. // 用于记录当前插入的格子数量
  60. nowNum = 0,
  61. cells = []; // 用于记录每个单独层对象</p><p style="margin-bottom: 14px;">// 获取列数
  62. function getColumnNum() {
  63. // 根据每列的宽度来计算总共的列数
  64. var columnNum = Math.floor(obody.clientWidth / (cellClientWidth + columnMarginRight));
  65. // 然后再设置owarp的宽度,是其保持居中
  66. owarp.style.width = columnNum * (cellClientWidth + columnMarginRight) – columnMarginRight + ‘px’;
  67. return columnNum;
  68. }</p><p style="margin-bottom: 14px;">// 创建格子
  69. function createCell(left, top, link, imgUrl, imgHeight, title) {
  70. var cssText = ‘position:absolute;left:’ + left + ‘px;top:’ + top + ‘px’;
  71. var inHTML = ‘<a href=”‘ + link + ‘” target=”_blank”><img src=”‘ + imgUrl + ‘” alt=”‘ + title + ‘” height=”‘ + imgHeight + ‘px”><p class=”title”>’ + title + ‘</p></a>’;
  72. //console.log(inHTML);
  73. var div = document.createElement(‘div’);
  74. div.className = ‘cell’;
  75. div.style.cssText = cssText;
  76. div.innerHTML = inHTML;
  77. return div;
  78. }</p><p style="margin-bottom: 14px;">// 插入数据
  79. function insert(data) {
  80. var fragElement = document.createDocumentFragment();
  81. if (data.length > 0) {
  82. for (var i = 0, n = data.length; i < n; i++) {
  83. var cell = createCell(-9999, -9999, data[i].link, data[i].imgUrl, data[i].height, data[i].title);
  84. fragElement.appendChild(cell);
  85. cells.push(cell);
  86. }
  87. owarp.appendChild(fragElement);
  88. }
  89. // 插入后再排序
  90. sort();
  91. }</p><p style="margin-bottom: 14px;">//排序
  92. function sort(){
  93. var num = getColumnNum(), left, top, column;
  94. //nowNum的作用是不让已经加载的数据重新计算定位排列
  95. for (var j = nowNum, k = cells.length; j < k; j++, nowNum++) {
  96. // 初始化top的值
  97. top = 0;
  98. // 获取当前为第几列
  99. column = j < num ? j : j % num;
  100. // 计算可以得到当前列的LEFT值
  101. left = column * (cellClientWidth + columnMarginRight);
  102. cells[j].style.left = left + ‘px’;
  103. if (j < num) {
  104. // 第一列top值为0
  105. cells[j].style.top = ’0px’;
  106. } else {
  107. // 计算TOP值,等于当前格子的顶上每列的高度相加
  108. for (var m = column; m < j; m = m + num) {
  109. top = top + cells[m].offsetHeight + columnMarginRight;
  110. }
  111. cells[j].style.top = top + ‘px’;
  112. }
  113. }
  114. }</p><p style="margin-bottom: 14px;">// resize 重新排列
  115. function resort() {
  116. // 设置nowNum=0即可重排
  117. nowNum = 0;
  118. // 重排
  119. sort();
  120. }
  121. // 暴露接口
  122. return {
  123. insert:insert,
  124. resort:resort
  125. }</p><p style="margin-bottom: 14px;">};
  126. var tool = {
  127. on:function (element, type, func) {
  128. if (element.addEventListener) {
  129. element.addEventListener(type, func, false); //false 表示冒泡
  130. } else if (element.attachEvent) {
  131. element.attachEvent(‘on’ + type, func);
  132. } else {
  133. element['on' + type] = func;
  134. }
  135. },
  136. getPageHeight:function () {
  137. return document.documentElement.scrollHeight || document.body.scrollHeight;
  138. },
  139. // 获取页面卷去的高度
  140. getScrollTop:function () {
  141. return document.documentElement.scrollTop || document.body.scrollTop;
  142. },
  143. // 获取页面可视区域宽度
  144. getClientHeigth:function () {
  145. return document.documentElement.clientHeight || document.body.clientHeight;
  146. },
  147. timer:null,
  148. timer2:null
  149. };
  150. var myWaterFull = waterFull({id:’warp’});
  151. // 初始化的数据
  152. myWaterFull.insert(data);
  153. tool.on(window, ‘scroll’, function () {
  154. clearTimeout(tool.timer); //清除上一次,性能优化
  155. tool.timer = setTimeout(function () {
  156. var height = tool.getPageHeight();
  157. var scrollTop = tool.getScrollTop();
  158. var clientHeight = tool.getClientHeigth();
  159. // 如果滚动到最底部,就加载
  160. if (scrollTop + clientHeight > height – 50) myWaterFull.insert(data);
  161. }, 500);
  162. });
  163. tool.on(window, ‘resize’, function () {
  164. clearTimeout(tool.timer2);
  165. tool.timer2 = setTimeout(function () {
  166. myWaterFull.resort();
  167. }, 500)
  168. })
  169. </script>
  170. </body>
  171. </html></p>
复制代码


DEMO下载:点击下载
明日上演示。。空间FTP连接不上
(本文来自 迅雷CUED )
回复

使用道具 举报

 发表于 2013-1-6 01:02:35
...

 来自 小调 的腾讯微博
回复

使用道具

Archiver|手机版|w3cvip.com  

GMT+8, 2013-2-1 10:37 , Processed in 0.065016 second(s), 31 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部