瀑布流加载的核心是精准判断懒加载时机并避免重复请求,通过监听滚动、比较最短列底部与视口距离、维护列高映射、逐条插入数据及 isLoading 锁机制实现均衡布局。

瀑布流加载的核心是监听滚动事件,判断容器底部是否接近视口底部,当满足条件时触发异步请求获取新数据,并追加到对应列中。关键在于“懒加载时机准确”和“避免重复请求”,而不是简单监听 scroll 就发请求。
监听页面滚动并判断加载时机
不能直接对 window 滚动做 throttle 后无脑请求,需计算“是否真的该加载”。常用方式是:取所有列高度的最小值(即最短列的底部),判断它是否进入视口底部一定距离(如 200px)内。
- 用 getBoundingClientRect() 获取最短列容器的 bottom 值
- 对比 window.innerHeight + window.scrollY 与该 bottom 值的差值
- 差值小于阈值(如 200)且当前没有加载中状态,才发起请求
维护多列数据与 DOM 映射关系
瀑布流不是把数据平铺追加,而是按列轮流插入——每次取最短列,把新卡片 append 到它里面。需要维护一个列容器元素数组和对应的高度缓存(或实时读取 offsetHeight)。
- 初始化时用 document.querySelectorAll('.column') 获取列容器
- 每次加载前遍历列元素,用 el.offsetHeight 找出最短列索引
- 新数据渲染后,立即更新该列高度(无需缓存,DOM 更新后 offsetHeight 自动生效)
控制并发与防抖,避免重复加载
滚动过程会高频触发,必须加锁机制。常见做法是用布尔标志位 + 请求完成回调解锁,而非仅靠防抖函数。
立即学习“Java免费学习笔记(深入)”;
- 定义 let isLoading = false,请求开始前设为 true,成功/失败后设为 false
- 在滚动检测逻辑开头加 if (isLoading) return
- 不推荐只用 setTimeout 防抖,因用户快速滚动可能跳过加载时机
加载完成后正确插入并更新布局
拿到新数据后,不要一次性全部渲染再找最短列;而应逐条分配——每条数据都重新找当前最短列插入,确保列高始终均衡。
- 对每项数据,调用 findShortestColumn() 获取目标列元素
- 用 columnEl.appendChild(cardEl) 插入,而非 innerHTML 拼接(避免重排开销)
- 插入后可选触发 columnEl.dispatchEvent(new Event('heightchange')) 供外部监听列变化
不复杂但容易忽略:首次加载完要手动触发一次加载检测,因为初始内容可能已撑满视口;另外移动端需监听 touchmove 并 preventDefault 的场景要小心,避免影响原生滚动。










