原生JavaScript实现瀑布流布局:原理与代码详解

花开有时
花开有时
发布时间:2026-10-13| 5人浏览过
原创

利用原生 JavaScript 实现瀑布流布局,主要依赖对页面可视区域的实时计算以及 DOM 元素的绝对定位。本文将解析如何通过 JS 获取窗口宽度、分配初始行数,并追踪每列高度以实现后续元素的智能排列。

瀑布流布局的核心逻辑

瀑布流(Waterfall Layout)是一种非对称的网格布局形式,其核心优势在于能够最大化利用屏幕垂直空间。在纯原生 JavaScript 环境下,实现该布局主要分为三个关键环节:

  1. 确定列数:根据父容器宽度和单个元素的固定宽度,计算出当前视口下每一行能容纳多少个元素。
  2. 首排占位:将第一行的元素依次放置在父容器中,作为基准列,并记录每列当前的累积高度。
  3. 后续定位:对于第二行及之后的元素,寻找当前高度最小的那一列,将新元素放置在该列的最下方(即 top 值为最小高度),并更新该列的高度。

这一过程需要配合窗口的 onscroll 事件,当用户滚动到底部时触发数据的追加和重新布局。

环境准备

为实现该效果,我们需要一个 HTML 结构和基础的 CSS 样式来辅助定位。

  • HTML 结构:创建一个 ID 为 main 的父容器,内部包含多个类名为 pin 的子元素,每个 pin 代表瀑布流中的一个格子。
  • CSS 样式:#main 需设置相对定位以方便内部子元素绝对定位;.pin 需设置浮动属性以便在第一排时能横向排列,而后续插入的元素由 JS 统一接管绝对定位。

JS 实现步骤

第1步:封装位置计算函数

这是瀑布流的核心算法。首先获取所有用于放置内容的元素数组,计算单列宽度,进而算出总列数。随后遍历这些元素,前 N 个(N 为列数)直接放入第一排并记录高度;后续元素则对比数组中的最低高度,找到对应索引后设置为绝对定位。

function waterfall(parentId, pinClassName) {
 var oParent = document.getElementById(parentId);
 // 获取所有的 pin 元素
 var aPins = getClassObj(oParent, pinClassName);
 
 // 获取单个 pin 的宽度
 var iPinW = aPins[0].offsetWidth;
 
 // 计算一行能容纳多少个 pin
 var num = Math.floor(document.documentElement.clientWidth / iPinW);
 
 // 限制列数不超过4列(避免过窄)
 if (num > 4) {
  num = 4; }
 
 // 设置父容器居中
 oParent.style.cssText = 'width:' + iPinW * num + 'px; margin: 0 auto;';
 
 // 初始化每列高度数组
 var pinHArr = [];
 
 for (var i = 0; i < aPins.length; i++) {
  var pinH = aPins[i].offsetHeight;
  
  // 如果是第一排的元素
  if (i < num) {
   pinHArr[i] = pinH;
  } else {
   // 找出高度最小的列索引
   var minH = Math.min.apply(null, pinHArr);
   var minHIndex = getMinHIndex(pinHArr, minH);
   
   // 绝对定位到最小高度列的下方
   aPins[i].style.position = 'absolute';
   aPins[i].style.top = minH + 'px';
   aPins[i].style.left = aPins[minHIndex].offsetLeft + 'px';
   
   // 更新该列的累计高度
   pinHArr[minHIndex] += aPins[i].offsetHeight;
  }
 }
}

第2步:实现滚动加载更多数据

为了实现用户体验良好的“无限加载”,我们需要判断用户是否即将滚动到页面底部。当条件满足时,模拟生成新的数据 DOM 节点,并再次调用 waterfall 函数进行重绘布局。

function checkscrollside() {
 var oParent = document.getElementById('main');
 var aPins = getClassObj(oParent, 'pin');
 
 // 如果高度不够,不加载
 if (aPins.length == 0) { return false; }
 
 // 获取最后一个元素距离顶部的距离加上一半自身高度
 var lastPinH = aPins[aPins.length - 1].offsetTop + Math.floor(aPins[aPins.length - 1].offsetHeight / 2);
 
 // 获取页面滚动的距离
 var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
 
 // 获取可视区域高度
 var documentH = document.documentElement.clientHeight;
 
 // 触发加载的条件:最后一个元素的一半已入视野
 return (lastPinH < scrollTop + documentH) ? true : false;
}

window.onscroll = function() {
 if (checkscrollside()) {
  // 此处应触发 AJAX 请求获取真实后端数据
  addNewElement(); 
  waterfall('main', 'pin'); // 重新计算布局
 }
};

第3步:工具函数与 DOM 操作

上述代码中用到了一些辅助函数,如根据 class 获取元素的数组 getClassObj,以及查找数组最小值索引的 getMinHIndex。这些是处理 DOM 列表时的标准做法:

function getClassObj(parent, className) {
 var obj = parent.getElementsByTagName('*');
 var pinS = [];
 for (var i = 0; i < obj.length; i++) {
  if (obj[i].className == className) {
   pinS.push(obj[i]);
  }
 };
 return pinS;
}

function getMinHIndex(arr, minH) {
 for (var i in arr) {
  if (arr[i] == minH) {
   return i;
  }
 }
}

视觉效果示例

经过上述代码处理后的页面,会呈现出参差不齐但视觉上整齐的排列效果。

注意事项与兼容性

在实际生产环境中,使用原生 JS 实现瀑布流需要注意以下几点:

  • 图片加载延迟:由于瀑布流的定位依赖于元素的实际高度,而在图片未加载完成前,DOM 高度通常为 0 或默认高度。因此,应在图片加载完毕后再执行 waterfall 函数,或者在预加载阶段预留高度占位。
  • 性能优化:频繁的重排(Reflow)会导致页面卡顿。建议在 onscroll 事件中增加防抖(Debounce)机制,例如在 50ms 内只触发一次布局计算。
  • 多端适配:当浏览器窗口大小改变时,列数可能发生变化。需监听 window.onresize 事件,重新调用布局函数以适应新的屏幕尺寸。

以上就是原生JavaScript实现瀑布流布局的详细内容,更多关于JS瀑布流实现的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。