使用 HTML + JavaScript 实现瀑布流布局(附源码地址)
|
admin
2026年1月17日 12:16
本文热度 7
|
瀑布流布局是一种优雅的网格展示方式,能够根据内容的高度自动排列,充分利用页面空间,给用户带来流畅的浏览体验。这种布局方式特别适合展示图片、卡片等不规则内容,让用户在滚动过程中感受到动态的视觉效果。通过合理的算法计算,可以让每一列的高度尽可能平衡,避免出现明显的高低差。本文将介绍如何使用 HTML、CSS 和 JavaScript 实现瀑布流布局。效果演示
瀑布流布局的核心交互是动态计算每个项目的最佳位置,确保整体布局紧凑且美观。当页面初次加载时,会显示预设数量的项目卡片,这些卡片的高度各不相同,但会在多个列中均匀分布。当用户向下滚动页面接近底部时,新的项目会自动加载并添加到最短的列中,保持整体布局的平衡。
页面结构
瀑布流容器区域
<div class="waterfall-container" id="waterfallColumns"></div>
加载指示器
<div class="loading" id="loadingIndicator">加载更多内容...</div>
核心功能实现
瀑布流布局类的设计与初始化
瀑布流布局的核心是 WaterfallLayout 类,它负责管理整个布局的逻辑。在构造函数中,我们接收容器ID和配置选项,其中配置选项包括列数、垂直间距和水平间距等参数。初始化过程包括设置初始列高度数组、计算每列宽度以及创建临时容器用于预计算元素高度。columnHeights 数组用来记录每列当前的总高度,初始值全部设为0。columnWidth 计算每列的实际宽度,考虑了容器宽度和列间的间隙。临时容器 tempContainer 是一个不可见的元素,用于预计算每个项目的实际高度,这样可以在不渲染到页面的情况下测量元素尺寸。class WaterfallLayout { constructor(containerId, options = {}) { this.container = document.getElementById(containerId); this.config = { columnCount: 4, verticalGap: 10, horizontalGap: 10, ...options }; this.init(); }
init() { this.columnHeights = new Array(this.config.columnCount).fill(0) const containerWidth = this.container.clientWidth; const totalHorizontalGap = this.config.horizontalGap * (this.config.columnCount - 1); this.columnWidth = Math.floor((containerWidth - totalHorizontalGap) / this.config.columnCount);
this.tempContainer = document.createElement('div'); this.tempContainer.style.cssText = `visibility: hidden; position: absolute; top: 0; left: 0; z-index: -1; overflow: hidden; width: ${this.columnWidth}px;`; document.body.appendChild(this.tempContainer); }}
获取最短列索引
getMinHeightColumnIndex 方法实现了找到当前高度最小列的功能。该方法遍历 columnHeights 数组,找出高度值最小的列的索引,返回该索引作为下一个项目应该放置的位置。这个算法确保了内容总是被添加到最短的列上,从而维持整体布局的平衡。getMinHeightColumnIndex() { let minHeight = Infinity; let minIndex = 0;
for (let i = 0; i < this.columnHeights.length; i++) { if (this.columnHeights[i] < minHeight) { minHeight = this.columnHeights[i]; minIndex = i; } } return minIndex;}
预计算项目高度
getItemHeight 方法是实现精确布局的重要组成部分。由于不同项目的高度可能不同,我们需要在将项目添加到布局之前先确定它的实际高度。该方法创建一个临时的DOM元素,应用与真实项目相同的样式和内容,然后测量其高度。这一步非常关键,因为它确保了在将元素定位到正确位置之前,我们已经知道了它的准确尺寸。getItemHeight(content) { const tempItem = document.createElement('div'); tempItem.className = 'waterfall-item'; tempItem.innerHTML = content; tempItem.style.width = `${this.columnWidth}px`;
this.tempContainer.appendChild(tempItem); const height = tempItem.offsetHeight; this.tempContainer.removeChild(tempItem);
return height;}
添加项目到布局
addItems 方法接收一个内容数组,将每个内容转换为瀑布流项目并放置在合适的位置。首先,方法计算每个项目应放置的位置,包括左侧偏移量和顶部偏移量。左侧偏移量取决于项目所在的列,顶部偏移量等于该列当前的总高度。在计算完所有项目的位置后,批量创建DOM元素并应用绝对定位样式将这些元素添加到容器中。addItems(contents) { const fragment = document.createDocumentFragment(); const positions = [];
contents.forEach(content => { const minColumnIndex = this.getMinHeightColumnIndex(); const left = minColumnIndex * (this.columnWidth + this.config.horizontalGap); const top = this.columnHeights[minColumnIndex]; const itemHeight = this.getItemHeight(content);
positions.push({ content, left, top, width: this.columnWidth, height: itemHeight });
this.columnHeights[minColumnIndex] = top + itemHeight + this.config.verticalGap; });
positions.forEach(pos => { const item = document.createElement('div'); item.className = 'waterfall-item'; item.innerHTML = pos.content; item.style.position = 'absolute'; item.style.width = `${pos.width}px`; item.style.left = `${pos.left}px`; item.style.top = `${pos.top}px`;
fragment.appendChild(item); });
this.container.appendChild(fragment); this.updateContainerHeight();}
源码地址
阅读原文:原文链接
该文章在 2026/1/19 11:00:28 编辑过