标题:原生JS实现美图瀑布流布局赏析
什么是瀑布流布局?
瀑布流布局是一种常见的网页布局方式,参考了瀑布流的设计,将页面上的元素按照一定规则排列,使得即便是不同尺寸、不同比例的元素也能够合理地被摆放。常见的网站如Pinterest、Instagram等都采用了瀑布流布局。
实现原理
实现瀑布流布局最核心的思路就是要能掌握两个问题:
-
如何确定每个元素的左右边距?
-
如何确定每个元素的上下边距?
对于第一个问题,我们一般采用的是“列宽一致,间距自适应”的方式。即我们先给出每一列的宽度,然后根据页面的实际宽度自动计算每一列之间的间距,进而实现元素的左右边距的自适应。
对于第二个问题,则需要考虑到瀑布流布局中,元素的上下位置是由它上方元素的高度所决定的。因此,我们需要获取每列中最小的元素高度,并让将要插入的元素放置在当前高度最小的那一列。
算法实现
下面我们就来详细讲解一下如何使用原生JS实现美图瀑布流布局。我们的算法实现分为三个主要的部分:初始化页面、加入新元素以及获取元素的信息。
初始化页面:init()
我们先来看一下如何初始化页面。在此之前,我们需要明确一些参数:
-
colCount:我们要展示的列数。
-
colWidth:每一列的宽度。
-
gap:每一列之间的间隙。
-
container:存放我们元素的容器。
有了这些参数之后,我们就可以开始初始化页面了。具体来讲,我们需要处理以下几个任务:
-
给每一列定位。
-
给每一列设置初始高度。
-
绑定resize事件,在窗口大小改变的时候重新定位列的位置。
代码实现如下:
let colCount, colWidth, gap, container, columns, itemWidth;
function init(container) {
colCount = 4;
colWidth = 200;
gap = 20;
columns = [];
itemWidth = colWidth - 2 * gap; // 减去边距
// 初始化每一列的位置
for (let i = 0; i < colCount; i++) {
let column = document.createElement("div");
column.className = "column";
column.style.left = (colWidth + gap) * i + "px";
container.appendChild(column);
columns.push(column);
}
// 初始化每一列的高度
reset();
// 绑定resize事件
window.addEventListener("resize", () => {
init(container);
});
}
function reset() {
// 初始化每一列的高度
for (let i = 0; i < colCount; i++) {
columns[i].style.top = 0;
columns[i].style.height = 0;
}
}
加入新元素:add()
有了初始化程序,我们就可以来看一下如何动态地添加元素了。关于如何动态地添加元素,我们可以使用ajax来获取数据,然后通过DOM操作将数据转化为元素,最后加入到我们的容器中。
在这个过程中,我们需要注意几个问题:
-
加入元素的时候要考虑到元素的高度,在加入之前我们需要先获取元素的高度。
-
加入元素时,我们需要将其放到当前高度最小的那一列,并且要重置该列的高度。
-
加入元素完成之后,要重新定位容器的位置,以免出现错列现象。
函数代码如下:
function add(item) {
let minHeight = columns[0].clientHeight;
let index = 0;
// 获取高度最小的列
for (let i = 0; i < colCount; i++) {
if (columns[i].clientHeight < minHeight) {
minHeight = columns[i].clientHeight;
index = i;
}
}
// 计算item的位置
let left = colWidth * index + gap * (index + 1);
let top = minHeight + gap;
// 新建item,并定位到容器中
let element = document.createElement("div");
element.className = "item";
element.style.width = itemWidth + "px";
element.style.left = left + "px";
element.style.top = top + "px";
element.innerHTML = `<img src="${item.src}" width="${item.width}" height="${item.height}">`;
columns[index].appendChild(element);
// 更新高度最小的列的高度
columns[index].style.height = `${minHeight + element.clientHeight + gap}px`;
// 更新容器的位置
container.style.height = `${Math.max(...getColumnHeights())}px`;
}
function getColumnHeights() {
return columns.map(column => column.clientHeight);
}
获取元素信息:getItemsList()
最后,我们还需要一个函数来获取元素的信息,方便后续的操作。我们可以使用一个for循环来遍历容器中的元素,然后将每一个元素的信息都存储到一个数组中。
function getItemsList() {
let itemList = [];
let items = container.querySelectorAll(".item");
for (let item of items) {
itemList.push({
src: item.querySelector("img").src,
width: item.clientWidth,
height: item.clientHeight
});
}
return itemList;
}
示例说明
我们来看两个简单的示例说明,展示瀑布流布局的具体实现效果。
示例1:使用Ajax获取数据
// 获取数据
fetch("https://picsum.photos/v2/list")
.then(response => response.json())
.then(data => {
init(document.querySelector(".container"));
for (let item of data) {
add({
src: item.download_url,
width: item.width,
height: item.height
});
}
});
该示例展示了如何使用fetch获取数据,然后将数据转化为元素直接加入到容器中。
示例2:使用静态数据
// 静态数据
let data = [
{
src: "https://picsum.photos/500/500",
width: 500,
height: 500
},
{
src: "https://picsum.photos/400/600",
width: 400,
height: 600
}
];
// 初始化页面
init(document.querySelector(".container"));
// 加入元素
for (let item of data) {
add(item);
}
该示例展示了如何使用静态数据,直接将数据转化为元素加入到容器中。
总结
通过本文的介绍,我们了解了瀑布流布局的原理和实现方法,掌握了如何使用原生JS实现美图瀑布流布局。使用瀑布流布局可以使我们的页面看起来更加美观,给用户带来更好的体验。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:原生JS实现美图瀑布流布局赏析 - Python技术站