You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13中react-window全屏滚动无限加载布局问题

解决Next.js 13中react-window无限滚动的滚动条与布局适配问题

核心问题分析

你当前的代码存在两个关键问题:

  • 直接使用window.innerHeight作为列表高度,未扣除页眉和页脚的占用空间,导致列表被页脚遮挡或滚动条高度异常
  • 绝对定位的容器破坏了根布局的flex流,无法与全局页眉、页脚正确共存

解决方案代码

组件修改(Wrapper.js)

import { useState, useEffect, useRef } from 'react';
import { InfiniteLoader, FixedSizeList } from 'react-window';
import styles from './Wrapper.module.css';

function Wrapper({ hasNextPage, isNextPageLoading, items, loadNextPage }) {
  const itemCount = hasNextPage ? items.length + 1 : items.length;
  const loadMoreItems = isNextPageLoading ? () => {} : loadNextPage;
  const isItemLoaded = (index) => !hasNextPage || index < items.length;
  const containerRef = useRef(null);
  const [listHeight, setListHeight] = useState(0);

  // 计算容器可用高度(自动扣除页眉页脚)
  useEffect(() => {
    const updateHeight = () => {
      if (containerRef.current) {
        setListHeight(containerRef.current.clientHeight);
      }
    };
    updateHeight();
    window.addEventListener('resize', updateHeight);
    return () => window.removeEventListener('resize', updateHeight);
  }, []);

  const Item = ({ index }) => {
    const content = !isItemLoaded(index) 
      ? "Loading..." 
      : items[index].name.first;

    return <div className={styles.item}>{content}</div>;
  };

  return (
    <div ref={containerRef} className={styles.scrollContainer}>
      <InfiniteLoader
        isItemLoaded={isItemLoaded}
        itemCount={itemCount}
        loadMoreItems={loadMoreItems}
      >
        {({ onItemsRendered, ref }) => (
          <FixedSizeList
            itemCount={itemCount}
            onItemsRendered={onItemsRendered}
            ref={ref}
            height={listHeight}
            width="100%"
            itemSize={35}
            style={{ overflowY: 'auto' }}
          >
            {Item}
          </FixedSizeList>
        )}
      </InfiniteLoader>
    </div>
  );
}

export default Wrapper;

CSS修改(Wrapper.module.css)

/* 滚动容器:由根布局flex分配剩余高度 */
.scrollContainer {
  flex: 1;
  width: 100%;
  overflow: hidden;
}

/* 新闻条目:限制最大宽度并居中 */
.item {
  max-width: 1920px;
  margin: 0 auto;
  padding: 8px 16px;
  border-bottom: 1px solid #eee;
}

/* 让滚动条和浏览器默认样式一致 */
.scrollContainer ::-webkit-scrollbar {
  width: 8px;
}

.scrollContainer ::-webkit-scrollbar-track {
  background: #f1f1f1;
}

.scrollContainer ::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 4px;
}

.scrollContainer ::-webkit-scrollbar-thumb:hover {
  background: #555;
}

根布局配置(app/layout.js)

确保根布局用flex垂直分布,让内容区占剩余高度:

import './globals.css';

export default function RootLayout({ children }) {
  return (
    <html lang="zh-CN">
      <body className={styles.pageContainer}>
        {/* 全局页眉 */}
        <header className={styles.header}>导航栏</header>
        {/* 内容区:由Wrapper组件填充 */}
        <main className={styles.main}>{children}</main>
        {/* 全局页脚 */}
        <footer className={styles.footer}>页脚</footer>
      </body>
    </html>
  );
}

对应的全局CSS(app/globals.css):

.pageContainer {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
  padding: 0;
}

.header {
  height: 60px; /* 替换为实际页眉高度 */
  background: #fff;
  border-bottom: 1px solid #eee;
}

.main {
  flex: 1;
  width: 100%;
}

.footer {
  height: 80px; /* 替换为实际页脚高度 */
  background: #f5f5f5;
  border-top: 1px solid #eee;
}

关键说明

  1. 高度适配:通过containerRef获取父容器的可用高度,自动扣除页眉页脚的固定高度,同时监听窗口大小变化实时更新
  2. 布局兼容:根布局用flex垂直分布,内容区占剩余空间,避免绝对定位破坏原有布局流
  3. 滚动条统一:通过CSS伪类自定义滚动条样式,和浏览器默认样式保持一致,固定在页面右侧
  4. 宽度控制:新闻条目设置max-width:1920px并居中,超出窗口宽度时两侧自动显示空白,符合需求

内容的提问来源于stack exchange,提问作者Caffeine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:27:41