瀑布流,是比较流行的一种网站页面,视觉表现为参差不齐的多栏布局,随着窗口的缩放会自动计算并重新排序;
下面是关于瀑布流的示例图:
实现过程
1.清除默认样式,先创建一个id 为 forcenter 的大盒子;
<div id='forcenter'></div>
2.在index.js 定义一个类,接收大盒子的id 和 需要加载的图片数组;
class waterfall {
constructor(obj) {
this.id = obj.id;
this.imgUrls = obj.imgUrls;
this.container = document.getElementById(this.id);
this.container.className = 'forcenter';
}
}
3.定义一个方法render,加载图片生成dom;
class waterfall {
constructor(obj) {
this.id = obj.id;
this.imgUrls = obj.imgUrls;
this.container = document.getElementById(this.id);
this.container.className = 'forcenter';
}
render() {
let flag = 0; // 用于检测每一张图片都加载完毕
//checkImage 用于防止图片路径不对,加载不出来,导致首屏没有执行resize
function checkImage(url) {
return new Promise((resolve, reject) => {
let img = new Image()
img.src = url
img.onload = () => {
resolve(img)
}
img.onerror = () => {
console.log(123);
reject()
}
})
}
this.imgUrls.map((item, i) => {
checkImage(item).then((img) => {
console.log("图片正确");
let div = document.createElement('div');
div.className = 'item';
flag++;
div.appendChild(img);
this.container.appendChild(div);
}).catch(() => {
flag++;
}).finally(() => {
//保证所有图片加载完之后再进行排列
if (flag === this.imgUrls.length) {
this.resize();
}
})
});
let styleE = document.createElement('style');
//给图片固定200px,保证宽度相同的情况下,高度自适应;
styleE.innerHTML = `div.item{
position: absolute;
transition: all .5s; /* 使过渡平滑*/
width : 200px;
height: auto;
padding:5px;
box-sizing: border-box; /* 非常重要,可将不必要的计算略去 */
}
div.item img{
width: 100%;
height: auto;
}
.forcenter{
position: relative;
margin: auto;
}`;
this.container.appendChild(styleE);
}
}
4.定义一个方法 resize ,排序图片
class waterfall {
constructor(obj) {
this.id = obj.id;
this.imgUrls = obj.imgUrls;
this.container = document.getElementById(this.id);
this.container.className = 'forcenter';
}
resize() {
function getMinH(arr) {
console.log(arr);
let flag = {
left: 0,
top: 0,
column: 0
}
arr.map((item, i) => {
if (flag.top === 0) {
flag.top = item;
} else {
if (flag.top > item) { // 找出高度最小的那一列
flag.top = item;
flag.left = 200 * i;
flag.column = i;
}
}
});
return flag;
}
function setDiv(item, left, top) {
item.style.left = left + 'px';
item.style.top = top + 'px';
}
let winW = window.innerWidth;
let itemNum = Math.floor(winW / 200); // 当每一个项的宽度都是固定的时候,需要计算出浏览器一行可以排列几个。
this.container.style.width = (itemNum * 200) + 'px'; // 用于居中的包裹盒子的宽度
let saveColumnHeight = []; // 定义一个数组,用于存储 每一列所有元素的高度 之和
let items = document.querySelectorAll('.item');
console.log(items)
for (let i = 0; i < items.length; i++) {
if (saveColumnHeight.length < itemNum) {
saveColumnHeight[i] = items[i].offsetHeight;// 当布局的元素还没占满一行时,继续向数组中添加第一行第i列的高度
setDiv(items[i], 200 * i, 0); // 放置div
} else { // 当已经占满一行时,就找出每一列的最小高度,然后当前的这个div放在高度最小的那一列
let pos = getMinH(saveColumnHeight); //去找高度最小的那一列
saveColumnHeight[pos.column] += items[i].offsetHeight;
setDiv(items[i], pos.left, pos.top); // 放置div
}
}
}
}
5.在页面中实例化 waterfall ,并执行实例中的方法,;
let W = new waterfall({
id: 'forcenter',
imgUrls: [
"https://gd-hbimg.huaban.com/01d4ff197f1b7c82c5c251e8e8236bb1ab7e0727651a5-WDx8ol_fw658webp",
"https://gd-hbimg.huaban.com/e320380f3c9178cc0b8310e7c03d8e241ccce13f1bf41d-iPTu0A_fw658webp",
"https://gd-hbimg.huaban.com/acde98e286be64cb57aa26b0e16668991796d122247433-sFxXXE_fw658webp",
"https://gd-hbimg.huaban.com/7ebc91824c83e5a6c5a95f432316297e0469b7fbb59fc-6f6dw7_fw658webp",
"https://gd-hbimg.huaban.com/75e24879bd50b6bdaee6897ecf7df8fed8fc6b321c1ae-IdBFAO_fw658webp",
"https://gd-hbimg.huaban.com/6c7c6cb1280654293598481ab4caa8ef308f6abc176736-9Dqd8L_fw658webp",
"https://gd-hbimg.huaban.com/23d645d1dbd6a45d37ad37e4b97d18be91e2dc49de203-lQ7f1c_fw658webp",
"https://gd-hbimg.huaban.com/144d28eaa9837fc65633e5ab05efcf95a3610c5913f7a5-S26C5f_fw658webp",
"https://gd-hbimg.huaban.com/f768bc96a779b0daf9dc046551624e76f07285fb13a61b-fPShae_fw658webp",
"https://gd-hbimg.huaban.com/4e94b094670cb92be05e115e7752e7e7a677721ace7ca-OmpKsJ_fw658webp",
"https://gd-hbimg.huaban.com/6378e2264b274c2a66c0d7a64243249d3cdd4990230087-YsZfHb_fw658webp",
"https://gd-hbimg.huaban.com/7879c0d70a9651bfef97dbdbca860d0173fb2083efdfa-JtEY7C_fw658webp",
"https://gd-hbimg.huaban.com/0ad9ee4917eb9bee29131a6305d91c1b512165f7ae91e-y5vGPb_fw658webp",
"https://gd-hbimg.huaban.com/18cfb795803a281a3fca234f05a0e8267eab4b08474f4-pvt6dW_fw658webp",
"https://gd-hbimg.huaban.com/b38ec047337c60dacec8532438e8df1f2f355e4a7739e2-lQkaGs_fw658webp",
"https://gd-hbimg.huaban.com/1cd188eba7137deba40617e49ff81cf9555cda3730edf-ddVRVj_fw658webp",
"https://gd-hbimg.huaban.com/d700b15123823599108913ceb94e188563594b2e7c2d4-M2VRbA_fw658webp",
"https://gd-hbimg.huaban.com/450d20605009f0f5389a31fed68e43d8ba1b93a8617d1-6dGTj0_fw658webp",
"https://gd-hbimg.huaban.com/e12930b69dc1e0bc3f5a152b7038ac250a9ec35792c97-G9OwPi_fw658webp",
"https://gd-hbimg.huaban.com/a9900bec233ff1393fa8e23e0e607f20a091c21e429e4-fneOUo_fw658webp",
]
})
window.onload = () => {
W.render()
}
window.onresize = () => {
W.resize()
}
6.结果展示
7.完整代码
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>瀑布流布局</title>
<meta name='viewport' content='width=device-width,initial-scale=1.0,user-scalable=no' />
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id='forcenter'></div>
<script src="./index.js"></script>
<script>
let W = new waterfall({
id: 'forcenter',
imgUrls: [
"https://gd-hbimg.huaban.com/01d4ff197f1b7c82c5c251e8e8236bb1ab7e0727651a5-WDx8ol_fw658webp",
"https://gd-hbimg.huaban.com/e320380f3c9178cc0b8310e7c03d8e241ccce13f1bf41d-iPTu0A_fw658webp",
"https://gd-hbimg.huaban.com/acde98e286be64cb57aa26b0e16668991796d122247433-sFxXXE_fw658webp",
"https://gd-hbimg.huaban.com/7ebc91824c83e5a6c5a95f432316297e0469b7fbb59fc-6f6dw7_fw658webp",
"https://gd-hbimg.huaban.com/75e24879bd50b6bdaee6897ecf7df8fed8fc6b321c1ae-IdBFAO_fw658webp",
"https://gd-hbimg.huaban.com/6c7c6cb1280654293598481ab4caa8ef308f6abc176736-9Dqd8L_fw658webp",
"https://gd-hbimg.huaban.com/23d645d1dbd6a45d37ad37e4b97d18be91e2dc49de203-lQ7f1c_fw658webp",
"https://gd-hbimg.huaban.com/144d28eaa9837fc65633e5ab05efcf95a3610c5913f7a5-S26C5f_fw658webp",
"https://gd-hbimg.huaban.com/f768bc96a779b0daf9dc046551624e76f07285fb13a61b-fPShae_fw658webp",
"https://gd-hbimg.huaban.com/4e94b094670cb92be05e115e7752e7e7a677721ace7ca-OmpKsJ_fw658webp",
"https://gd-hbimg.huaban.com/6378e2264b274c2a66c0d7a64243249d3cdd4990230087-YsZfHb_fw658webp",
"https://gd-hbimg.huaban.com/7879c0d70a9651bfef97dbdbca860d0173fb2083efdfa-JtEY7C_fw658webp",
"https://gd-hbimg.huaban.com/0ad9ee4917eb9bee29131a6305d91c1b512165f7ae91e-y5vGPb_fw658webp",
"https://gd-hbimg.huaban.com/18cfb795803a281a3fca234f05a0e8267eab4b08474f4-pvt6dW_fw658webp",
"https://gd-hbimg.huaban.com/b38ec047337c60dacec8532438e8df1f2f355e4a7739e2-lQkaGs_fw658webp",
"https://gd-hbimg.huaban.com/1cd188eba7137deba40617e49ff81cf9555cda3730edf-ddVRVj_fw658webp",
"https://gd-hbimg.huaban.com/d700b15123823599108913ceb94e188563594b2e7c2d4-M2VRbA_fw658webp",
"https://gd-hbimg.huaban.com/450d20605009f0f5389a31fed68e43d8ba1b93a8617d1-6dGTj0_fw658webp",
"https://gd-hbimg.huaban.com/e12930b69dc1e0bc3f5a152b7038ac250a9ec35792c97-G9OwPi_fw658webp",
"https://gd-hbimg.huaban.com/a9900bec233ff1393fa8e23e0e607f20a091c21e429e4-fneOUo_fw658webp",
]
})
window.onload = () => {
W.render()
}
window.onresize = () => {
W.resize()
}
</script>
</body>
</html>
index.js
class waterfall {
constructor(obj) {
this.id = obj.id;
this.imgUrls = obj.imgUrls;
this.container = document.getElementById(this.id);
this.container.className = 'forcenter';
}
render() {
let flag = 0; // 用于检测每一张图片都加载完毕
function checkImage(url) {
return new Promise((resolve, reject) => {
let img = new Image()
img.src = url
img.onload = () => {
resolve(img)
}
img.onerror = () => {
console.log(123);
reject()
}
})
}
this.imgUrls.map((item, i) => {
checkImage(item).then((img) => {
console.log("图片正确");
let div = document.createElement('div');
div.className = 'item';
flag++;
div.appendChild(img);
this.container.appendChild(div);
}).catch(() => {
flag++;
}).finally(() => {
if (flag === this.imgUrls.length) {
this.resize();
}
})
});
let styleE = document.createElement('style');
styleE.innerHTML = `div.item{
position: absolute;
transition: all .5s; /* 使过渡平滑*/
width : 200px;
height: auto;
padding:5px;
box-sizing: border-box; /* 非常重要,可将不必要的计算略去 */
}
div.item img{
width: 100%;
height: auto;
}
.forcenter{
position: relative;
margin: auto;
}`;
this.container.appendChild(styleE);
}
resize() {
function getMinH(arr) {
console.log(arr);
let flag = {
left: 0,
top: 0,
column: 0
}
arr.map((item, i) => {
if (flag.top === 0) {
flag.top = item;
} else {
if (flag.top > item) { // 找出高度最小的那一列
flag.top = item;
flag.left = 200 * i;
flag.column = i;
}
}
});
return flag;
}
function setDiv(item, left, top) {
item.style.left = left + 'px';
item.style.top = top + 'px';
}
let winW = window.innerWidth;
let itemNum = Math.floor(winW / 200); // 当每一个项的宽度都是固定的时候,需要计算出浏览器一行可以排列几个。
this.container.style.width = (itemNum * 200) + 'px'; // 用于居中的包裹盒子的宽度
let saveColumnHeight = []; // 定义一个数组,用于存储 每一列所有元素的高度 之和
let items = document.querySelectorAll('.item');
console.log(items)
for (let i = 0; i < items.length; i++) {
if (saveColumnHeight.length < itemNum) {
saveColumnHeight[i] = items[i].offsetHeight;// 当布局的元素还没占满一行时,继续向数组中添加第一行第i列的高度
setDiv(items[i], 200 * i, 0); // 放置div
} else { // 当已经占满一行时,就找出每一列的最小高度,然后当前的这个div放在高度最小的那一列
let pos = getMinH(saveColumnHeight); //去找高度最小的那一列
saveColumnHeight[pos.column] += items[i].offsetHeight;
setDiv(items[i], pos.left, pos.top); // 放置div
}
}
}
}
声明:本文所有素材来源:花瓣网 - 陪你做生活的设计师(创意灵感天堂,搜索、发现设计灵感、设计素材)