Javascript 瀑布流实现的两种方式:固定列数的浮动布局与绝对定位自适应宽度
2012-09-10 22:36
1026 查看
瀑布流已经火了一段时间了,自己最近研究了一下,网上关于瀑布流的帖子也很多,网上一般是说三种方式,固定列数的浮动布局,CSS3列布局,绝对定位布局
推荐两个关于瀑布流的帖子,写得比我详细多了:
迅雷的:http://cued.xunlei.com/log031
张鑫旭的:网址太长点我
这里主要是记录一下我的实现方式,用数组模拟的数据,也可以用AJAX实现读取数据,底部提供DEMO代码下载!
一、固定列数的浮动布局
这种方式简单适用,先按照列数把布局固定好,然后在滚动事件中分别在每一列插入相应的数据既可,代码比较简单:
其实就一个滚动加载事件。我这里没有做按高低排序。
点击查看DEMO演示
代码如下:
View Code
二、绝对定位实现的瀑布流,宽度自适应,resize重排
绝对定位实现方式因为要获取每格的高度,然后根据高度来计算定位位置,所以必须要知道图片的高度,如果没有高度,定位就不准确,所以传递数据的时候需要图片的高度。
点击查看DEMO演示
我是这样计算绝对定位的位置的,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);
这里可以把每格的高度通过对象的属性记录下来,以免每次都进行offsetHeight的获取,我的代码里面没有体现出来。
这个计算就通过一个循环来实现:
计算定位的代码如下:
瀑布流绝对定位总代码如下:
DEMO下载:点击下载
推荐两个关于瀑布流的帖子,写得比我详细多了:
迅雷的:http://cued.xunlei.com/log031
张鑫旭的:网址太长点我
这里主要是记录一下我的实现方式,用数组模拟的数据,也可以用AJAX实现读取数据,底部提供DEMO代码下载!
一、固定列数的浮动布局
这种方式简单适用,先按照列数把布局固定好,然后在滚动事件中分别在每一列插入相应的数据既可,代码比较简单:
其实就一个滚动加载事件。我这里没有做按高低排序。
点击查看DEMO演示
代码如下:
View Code
/* * * 基于固定宽度的浮动定位的瀑布流 * 实现简单,其实就是一个滚动加载数据而已 * 缺点布局不随宽度的变化而改变,如果有图片特别长的时候,最高的列与最低的列有可能差距大,空白大 * by VVG http://www.cnblogs.com/NNUF/ */ var WaterFull = { $:function(id){return document.getElementById(id);}, // 每次滚动需要加载的数据,可以用ajax替代读取,每次分批加载 data:[{imgUrl:'images/01.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位01'}, {imgUrl:'images/02.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位02'}, {imgUrl:'images/03.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位03'}, {imgUrl:'images/05.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位04'}, {imgUrl:'images/06.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位05'}, {imgUrl:'images/07.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位06'}, {imgUrl:'images/08.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位07'}, {imgUrl:'images/09.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位08'}, {imgUrl:'images/10.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位09'}, {imgUrl:'images/11.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位10'}, {imgUrl:'images/12.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位11'}, {imgUrl:'images/13.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位12'}, {imgUrl:'images/14.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位13'}, {imgUrl:'images/15.jpg',link:'javascript:void(0)',title:'瀑布流浮动定位14'} ], createChild:function(link,imagesUrl,title){ var str = '<a href="' + link + '"><img src="' + imagesUrl + '"></a>' + '<p class="title">' + title + '</p>'; var div = document.createElement('div'); div.className = 'water'; div.innerHTML = str; return div; }, //绑定事件 on:function(element, type, func) { if (element.addEventListener) { element.addEventListener(type, func, false); //false 表示冒泡 } else if (element.attachEvent) { element.attachEvent('on' + type, func); } else { element['on' + type] = func; } }, //获取列高度,返回数组,从小到大排序 getRowByHeight:function(){ var row = [this.$('row1'),this.$('row2'),this.$('row3'),this.$('row4')]; var height = []; for(var i = 0;row[i];i++){ row[i].height = row[i].offsetHeight; height.push(row[i]); } // 对高度进行排序,低--》高,保证最矮的优先加载 height.sort(function(a,b){ return a.height - b.height; }); return height; }, //获取页面总高度(总高度 = 卷去高度 + 可视区域高度) getPageHeight:function(){ return document.documentElement.scrollHeight || document.body.scrollHeight ; }, // 获取页面卷去的高度 getScrollTop:function(){ return document.documentElement.scrollTop || document.body.scrollTop; }, // 获取页面可视区域宽度 getClientHeigth:function(){ return document.documentElement.clientHeight || document.body.clientHeight; }, append:function(){ var i = 0,rows = this.getRowByHeight(),div,k; for(;this.data[i];i++){ div = this.createChild(this.data[i].link, this.data[i].imgUrl,this.data[i].title); // 因为是4列,所以数据以4列一个轮回加载 k = ((i+1)>4)?i%4:i; // 在列上添加数据 rows[k].appendChild(div); } }, onScroll:function(){ // 获取高度等数据 var height = WaterFull.getPageHeight(); var scrollTop = WaterFull.getScrollTop(); var clientHeight = WaterFull.getClientHeigth(); // 如果滚动到最底部,就加载 if(scrollTop + clientHeight > height - 50){ WaterFull.append(); } }, timer:null }; WaterFull.on(window, 'scroll',function(){ clearTimeout( WaterFull.timer ); //清除上一次,性能优化 WaterFull.timer = setTimeout(WaterFull.onScroll,500); });
二、绝对定位实现的瀑布流,宽度自适应,resize重排
绝对定位实现方式因为要获取每格的高度,然后根据高度来计算定位位置,所以必须要知道图片的高度,如果没有高度,定位就不准确,所以传递数据的时候需要图片的高度。
点击查看DEMO演示
我是这样计算绝对定位的位置的,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);
这里可以把每格的高度通过对象的属性记录下来,以免每次都进行offsetHeight的获取,我的代码里面没有体现出来。
这个计算就通过一个循环来实现:
计算定位的代码如下:
function sort(){ var num = getColumnNum(), left, top, column; //nowNum的作用是不让已经加载的数据重新计算定位排列 for (var j = nowNum, k = cells.length; j < k; j++, nowNum++) { // 初始化top的值 top = 0; // 获取当前为第几列 column = j < num ? j : j % num; // 计算可以得到当前列的LEFT值 left = column * (cellClientWidth + columnMarginRight); cells[j].style.left = left + 'px'; if (j < num) { // 第一列top值为0 cells[j].style.top = '0px'; } else { // 计算TOP值,等于当前格子的顶上每列的高度相加 for (var m = column; m < j; m = m + num) { top = top + cells[m].offsetHeight + columnMarginRight; } cells[j].style.top = top + 'px'; } } }
瀑布流绝对定位总代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>瀑布流布局(绝对定位)</title>
<style type="text/css">
html, body{
height:100%
}
html, body, #warp p{
margin:0;
padding:0
}
#warp{
margin:20px auto;
position:relative;
min-height:1000px;
}
#warp .cell{
padding:10px;
border:1px solid #ccc;
box-shadow:2px 2px 5px #ccc;
overflow:hidden;
}
#warp .cell a{
text-decoration:none;
color:#878787;
font:14px/1.5em Microsoft YaHei;
}
img{ border:none; }
</style>
</head>
<body>
<div id="warp" class="warp clearfix"></div>
<script type="text/javascript">
var data = [
{imgUrl:'images/01.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位01', height:273},
{imgUrl:'images/02.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位02', height:144},
{imgUrl:'images/03.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位03', height:168},
{imgUrl:'images/04.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位04', height:275},
{imgUrl:'images/05.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位05', height:288},
{imgUrl:'images/06.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位05', height:272},
{imgUrl:'images/07.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位06', height:285},
{imgUrl:'images/08.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位07', height:282},
{imgUrl:'images/09.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位08', height:190},
{imgUrl:'images/10.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位09', height:236},
{imgUrl:'images/11.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位10', height:225},
{imgUrl:'images/12.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位11', height:264},
{imgUrl:'images/13.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位12', height:144},
{imgUrl:'images/14.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位13', height:192},
{imgUrl:'images/15.jpg', link:'javascript:void(0)', title:'瀑布流绝对定位14', height:343}
];
var waterFull = function (options) {
var id = options.id,
picWidth = options.picWidth || 190,
columnPadding = options.columnPadding || 10,
columnBorder = options.columnBorder || 1,
columnMarginRight = options.columnMargin || 20,
// 格子总宽度
cellClientWidth = picWidth + columnPadding * 2 + columnBorder * 2,
obody = document.getElementsByTagName('body')[0],
owarp = document.getElementById(id),
// 用于记录当前插入的格子数量
nowNum = 0,
cells = []; // 用于记录每个单独层对象
// 获取列数
function getColumnNum() {
// 根据每列的宽度来计算总共的列数
var columnNum = Math.floor(obody.clientWidth / (cellClientWidth + columnMarginRight));
// 然后再设置owarp的宽度,是其保持居中
owarp.style.width = columnNum * (cellClientWidth + columnMarginRight) - columnMarginRight + 'px';
return columnNum;
}
// 创建格子
function createCell(left, top, link, imgUrl, imgHeight, title) {
var cssText = 'position:absolute;left:' + left + 'px;top:' + top + 'px';
var inHTML = '<a href="' + link + '" target="_blank"><img src="' + imgUrl + '" alt="' + title + '" height="' + imgHeight + 'px"><p class="title">' + title + '</p></a>';
//console.log(inHTML);
var div = document.createElement('div');
div.className = 'cell';
div.style.cssText = cssText;
div.innerHTML = inHTML;
return div;
}
// 插入数据
function insert(data) {
var fragElement = document.createDocumentFragment();
if (data.length > 0) {
for (var i = 0, n = data.length; i < n; i++) {
var cell = createCell(-9999, -9999, data[i].link, data[i].imgUrl, data[i].height, data[i].title);
fragElement.appendChild(cell);
cells.push(cell);
}
owarp.appendChild(fragElement);
}
// 插入后再排序
sort();
}
//排序
function sort(){ var num = getColumnNum(), left, top, column; //nowNum的作用是不让已经加载的数据重新计算定位排列 for (var j = nowNum, k = cells.length; j < k; j++, nowNum++) { // 初始化top的值 top = 0; // 获取当前为第几列 column = j < num ? j : j % num; // 计算可以得到当前列的LEFT值 left = column * (cellClientWidth + columnMarginRight); cells[j].style.left = left + 'px'; if (j < num) { // 第一列top值为0 cells[j].style.top = '0px'; } else { // 计算TOP值,等于当前格子的顶上每列的高度相加 for (var m = column; m < j; m = m + num) { top = top + cells[m].offsetHeight + columnMarginRight; } cells[j].style.top = top + 'px'; } } }
// resize 重新排列
function resort() {
// 设置nowNum=0即可重排
nowNum = 0;
// 重排
sort();
}
// 暴露接口
return {
insert:insert,
resort:resort
}
};
var tool = {
on:function (element, type, func) {
if (element.addEventListener) {
element.addEventListener(type, func, false); //false 表示冒泡
} else if (element.attachEvent) {
element.attachEvent('on' + type, func);
} else {
element['on' + type] = func;
}
},
getPageHeight:function () {
return document.documentElement.scrollHeight || document.body.scrollHeight;
},
// 获取页面卷去的高度
getScrollTop:function () {
return document.documentElement.scrollTop || document.body.scrollTop;
},
// 获取页面可视区域宽度
getClientHeigth:function () {
return document.documentElement.clientHeight || document.body.clientHeight;
},
timer:null,
timer2:null
};
var myWaterFull = waterFull({id:'warp'});
// 初始化的数据
myWaterFull.insert(data);
tool.on(window, 'scroll', function () {
clearTimeout(tool.timer); //清除上一次,性能优化
tool.timer = setTimeout(function () {
var height = tool.getPageHeight();
var scrollTop = tool.getScrollTop();
var clientHeight = tool.getClientHeigth();
// 如果滚动到最底部,就加载
if (scrollTop + clientHeight > height - 50) myWaterFull.insert(data);
}, 500);
});
tool.on(window, 'resize', function () {
clearTimeout(tool.timer2);
tool.timer2 = setTimeout(function () {
myWaterFull.resort();
}, 500)
})
</script>
</body>
</html>
DEMO下载:点击下载
相关文章推荐
- CSS float的初步理解:用两种不同的方式来实现一个三列布局,其中左侧和右侧的部分宽度固定,中间部分宽度随浏览器宽度的变化而自适应变化
- 用两种不同的方式来实现一个三列布局,其中左侧和右侧的部分宽度固定,中间部分宽度随浏览器宽度的变化而自适应变化
- 利用绝对定位实现两列右边固定宽度左边自适应布局
- 用两种不同的方式来实现一个三列布局,其中左侧和右侧的部分宽度固定,中间部分宽度随浏览器宽度的变化而自适应变化
- 用两种不同的方法来实现一个两列布局,其中左侧部分宽度固定、右侧部分宽度随浏览器宽度的变化而自适应变化
- 实现左边div固定宽度,右边div自适应撑满剩下的宽度的布局方式
- 一列固定宽度布局和背景图片绝对定位的实现代码
- 瀑布流布局的两种实现方式:传统多列浮动和绝对定位布局
- 解析瀑布流布局:JS+绝对定位的实现
- javascript自适应宽度的瀑布流实现思路
- CSS实现自适应高度布局:头部底部固定,中间自适应铺满屏幕剩余高度,中间盒子里左盒子固定右盒子自适应宽度
- 三栏自适应布局实现(左右固定宽度,中间自适应)
- [WebApp]定宽网页设计下,固定宽度布局开发WebApp并实现多终端下WebApp布局自适应
- 定宽网页设计下,固定宽度布局开发WebApp并实现多终端下WebApp布局自适应
- 总结css实现固定和自适应宽度混合的多栏布局实现方法
- 解析瀑布流布局:JS+绝对定位的实现
- CSS基础篇--css实现两列布局,一列固定宽度,一列宽度自适应方法
- 【CSS】瀑布流布局的两种方式:传统多列浮动和绝对定位布局
- 关于ie6中绝对定位或浮动的div中既有向左float也有向右float时候如何让外层div自适应宽度的解决方案--
- javascript自适应宽度的瀑布流实现思路