瀑布流布局
2017-08-28 本文已影响3人
DeeJay_Y
瀑布流:每个内容的宽度相等,高度是随机的
布局的基本原则,第一排排满之后,下面的元素将放到高度最短的那一列下面。
实现的基本思路:
- 需要创建一个数组,这个数组存储的每一项都为对应列的高度,而下标就为当前的列
- 需要得到每个元素的宽度
实现举例:
<style>
.content {
position: relative;
}
.item {
/*绝对定位,并且每个元素的宽度是一定的*/
position: absolute;
width: 200px;
margin-right: 10px;
margin-top: 10px;
transition: all 1s;
}
.h1 {
height: 200px;
background: #f4b300;
}
.h2 {
height: 300px;
background: #691bbb;
}
.h3 {
height: 400px;
background: #006ac1;
}
</style>
</head>
<body>
<div class="content">
<div class="item h1">1</div>
<div class="item h3">2</div>
<div class="item h2">3</div>
<div class="item h2">4</div>
<div class="item h3">5</div>
<div class="item h1">6</div>
<div class="item h2">7</div>
<div class="item h3">8</div>
<div class="item h1">9</div>
<div class="item h2">10</div>
<div class="item h3">11</div>
<div class="item h3">12</div>
<div class="item h2">13</div>
<div class="item h1">14</div>
</div>
结构和样式如上,h1,h2,h3用来模拟随机的高度。
JS部分如下:
<script src="../jquery-3.2.1.min.js"></script>
<script>
// 创建数组
var itemArr = [];
//得到数组一共有多少项,即要排列的元素到底有几列,可以通过content的宽度除以item的宽度,然后进行取整就能得到总共有多少列
var itemColumn = parseInt($('.content').width() / $('.item').width());
// console.log(itemColumn)
//进行数组的初始化,有itemColumn项,每项都先设为0,表示当前没有元素,高度为0
for (var i = 0; i < itemColumn; i ++) {
itemArr[i] = 0;
}
//数组初始化完毕,然后涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法
//进行遍历所有的item,将每个item放到当前高度最短的那一列的下边
$('.item').each(function () {
var minHeight = Math.min.apply(null,itemArr);//数组中值最小的一项,即高度最短的那一列的高度值
var minIndex = itemArr.indexOf(minHeight); // 对应列的下标
$(this).css({
left: minIndex * $('.item').outerWidth(true), //这个outerWidth,有true代表包括margin,不写true代表只包括border
top: minHeight,
})
itemArr[minIndex] += $(this).outerHeight(true); //放置完当前遍历元素时,将相应的高度加到当前列的高度上
// console.log('h',minHeight)
// console.log('i',minIndex);
})
</script>
代码的整体思路已经很清晰了,但是有地方需要注意:
- 涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法。使用Math.min要结合apply()
- $('.item').outerWidth(true)
然后基本效果就达到了,但是需要监听窗口大小改变的事件,如果窗口大小改变,重新排列一下。所以我们封装一下我们得到的代码。加上监听事件
waterFall(); //页面初始化时先执行一次出现布局
$(window).on('resize',function () { // 监听浏览器窗口大小改变的事件
waterFall();
})
function waterFall() {
// 创建数组
var itemArr = [];
//得到数组一共有多少项,即要排列的元素到底有几列,可以通过content的宽度除以item的宽度,然后进行取整就能得到总共有多少列
var itemColumn = parseInt($('.content').width() / $('.item').width());
// console.log(itemColumn)
//进行数组的初始化,有itemColumn项,每项都先设为0,表示当前没有元素,高度为0
for (var i = 0; i < itemColumn; i ++) {
itemArr[i] = 0;
}
//数组初始化完毕,然后涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法
//进行遍历所有的item,将每个item放到当前高度最短的那一列的下边
$('.item').each(function () {
var minHeight = Math.min.apply(null,itemArr);//数组中值最小的一项,即高度最短的那一列的高度值
var minIndex = itemArr.indexOf(minHeight); // 对应列的下标
$(this).css({
left: minIndex * $('.item').outerWidth(true), //这个outerWidth,有true代表包括margin,不写true代表只包括border
top: minHeight,
})
itemArr[minIndex] += $(this).outerHeight(true); //放置完当前遍历元素时,将相应的高度加到当前列的高度上
// console.log('h',minHeight)
// console.log('i',minIndex);
})
}
此时窗口大小改变时也会相应的重新布局了。还可以进一步封装代码,创建一个对象,把要执行的代码return出来,函数体放到对象内部的属性中。
var begin = {
run: run,
};
begin.run();
function run () {
function waterFall() {
// 创建数组
var itemArr = [];
//得到数组一共有多少项,即要排列的元素到底有几列,可以通过content的宽度除以item的宽度,然后进行取整就能得到总共有多少列
var itemColumn = parseInt($('.content').width() / $('.item').width());
// console.log(itemColumn)
//进行数组的初始化,有itemColumn项,每项都先设为0,表示当前没有元素,高度为0
for (var i = 0; i < itemColumn; i ++) {
itemArr[i] = 0;
}
//数组初始化完毕,然后涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法
//进行遍历所有的item,将每个item放到当前高度最短的那一列的下边
$('.item').each(function () {
var minHeight = Math.min.apply(null,itemArr);//数组中值最小的一项,即高度最短的那一列的高度值
var minIndex = itemArr.indexOf(minHeight); // 对应列的下标
$(this).css({
left: minIndex * $('.item').outerWidth(true), //这个outerWidth,有true代表包括margin,不写true代表只包括border
top: minHeight,
})
itemArr[minIndex] += $(this).outerHeight(true); //放置完当前遍历元素时,将相应的高度加到当前列的高度上
// console.log('h',minHeight)
// console.log('i',minIndex);
})
}
return (function () {
waterFall(); //页面初始化时先执行一次出现布局
$(window).on('resize',function () { // 监听浏览器窗口大小改变的事件
waterFall();
})
})();
}
封装代码如上所示,把函数体放到run()中,作为值传递给begin对象的run属性,return的是包含我们想要执行的代码的立即执行函数,这样我们想要开始的时候,只需要调用begin对象的run属性即可。