您的位置:首页 > Web前端 > JavaScript

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

2012-09-10 22:36 1026 查看
瀑布流已经火了一段时间了,自己最近研究了一下,网上关于瀑布流的帖子也很多,网上一般是说三种方式,固定列数的浮动布局,CSS3列布局,绝对定位布局

推荐两个关于瀑布流的帖子,写得比我详细多了:

迅雷的: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下载:点击下载

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐