如何用原生js实现瀑布流布局?
概念:
瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动天向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinteres,逐渐在国内流行开来。国内大多数清新站基本为这类风格。
布局特点:
-
琳琅满目:整版以图片为主,大小不一的图片按照一定的规律排列。
-
唯美:图片的风格以唯美的图片为主。
-
操作简单:在浏览网站的时候只需要轻轻滑动一下鼠标滚轮,一切的美妙的图片精彩便可呈现在你面前。
应用场景:
-
例如下图:苏宁的官网
-
例如下图:网站布局
原理:
瀑布流布局的特点是等宽不等高。为了让最后一行的差距最小,从第二行开始,需要将图片放在第一行最矮的图片下面,以此类推。父元素设置为相对定位,图片所在元素设置为绝对定位。然后通过设置 top 值和 left 值定位每个元素。
简单来说:
-
将图片宽度固定,用浏览器窗口大小除以每个图片的宽度,求出要分成的列数
-
将每个图片定位
-
每次找到最小高度的列,将图片加到该列后
面向过程-具体代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>面向过程:模拟瀑布流</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 600px;
margin: 0 auto;
border: 1px solid #000;
position: relative;
}
.box>div {
width: 100px;
border: 1px solid pink;
box-sizing: border-box;
position: absolute;
}
</style>
</head>
<body>
<div class="box">
</div>
<script>
// 瀑布流核心:
// 1.将图片宽度固定,用浏览器窗口大小除以每个图片的宽度,求出要分成的列数
// 2.将每个图片定位
// 3.每次找到最小高度的列,将图片加到该列后
var box = document.querySelector('.box');
// 生成随机数的函数:得到一个两数之间的随机整数(不包含最大值和最小值)
function rdNum(min, max) {
return Math.ceil(Math.random() * (max - min)) + min
}
// 封装函数:实现获取数组中的最小值
function getMin(abc) {
return Math.min.apply(null, abc);
}
// 记录每一列中每个元素的高度
var arr = [0, 0, 0, 0];
// 动态生成随机的高度,去数组中最小的那一列,将数字累加上去
for (var i = 0; i < 20; i++) {
// 获取每一列数组中的最小值
var minVal = getMin(arr);
// 获取每一列的数组的最小值的索引
var index = arr.findIndex(function(item, index) {
return item === minVal;
});
// 生成一个随机数---也就是每个div的高度
var randomNum = rdNum(40, 150);
// 动态创建div标签
var div = document.createElement('div');
// div的内容是索引
div.innerText = i;
// box的宽度
var boxWidth = box.offsetWidth;
console.log(boxWidth);
// 设置div的高
div.style.height = randomNum + 'px';
console.log(div.style.height);
// 设置每个div的到左边的距离
div.style.left = index * (((boxWidth - 4 * 100) / (4 - 1)) + 100) + 'px';
// 到顶部的距离也就是每一列的最小值
div.style.top = minVal + 'px';
box.appendChild(div);
// 将随机数累加到数组中最小的那一列的数组元素
arr[index] += randomNum;
//randomNum每个div的高度 //index获取每一列的数组的最小值的索引 //arr[index]就是每一列最小数组元素的值
console.log(arr)
}
box.style.height = Math.max.apply(null, arr) + 'px'
</script>
</body>
</html>
面向对象-具体代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>面向对象:模拟瀑布流</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 600px;
margin: 0 auto;
border: 1px solid red;
position: relative;
}
.box>div {
border: 1px solid orange;
box-sizing: border-box;
position: absolute;
}
.container {
width: 800px;
margin: 100px auto;
border: 1px solid #000;
}
.container>div {
border: 1px solid orange;
box-sizing: border-box;
}
</style>
</head>
<body>
<div class="box"></div>
<div class="container"></div>
<script>
function Pubu(obj) {
this.box = document.querySelector(obj.el);
this.column = obj.column;
this.width = obj.width;
this.show();
}
Pubu.prototype.rdNum = function(max, min) {
return Math.ceil(Math.random() * (max - min)) + min;
}
Pubu.prototype.getMin = function(abc) {
return Math.min.apply(null, abc);
}
Pubu.prototype.getIndex = function(abc, def) {
return abc.findIndex(function(item) {
return item === def;
})
}
Pubu.prototype.createDv = function(i, randomNum, index, minVal) {
var dv = document.createElement('div');
dv.innerText = i;
dv.style.width = this.width + 'px';
dv.style.position = 'absolute';
dv.style.height = randomNum + 'px';
dv.style.left = index * ((this.box.offsetWidth - this.width * this.column) / (this.column - 1) + this.width) + 'px';
dv.style.top = minVal + 'px';
this.box.appendChild(dv);
}
Pubu.prototype.show = function() {
this.box.style.position = 'relative';
var arr = new Array(this.column);
arr.fill(0);
for (var i = 0; i < 20; i++) {
var minVal = this.getMin(arr);
var index = this.getIndex(arr, minVal);
var randomNum = this.rdNum(40, 150);
this.createDv(i, randomNum, index, minVal);
arr[index] += randomNum;
this.box.style.height = Math.max.apply(null, arr) + 'px';
}
}
new Pubu({
el: '.box',
column: 4,
width: 110
})
new Pubu({
el: '.container',
column: 7,
width: 100
})
</script>
</body>
- 效果图: