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

React无限滚动出现双滚动条,仅需保留窗口滚动条求助

我来帮你解决这个双滚动条+窗口滚动触发无限滚动的问题!

方案一:改用窗口滚动触发无限滚动(推荐,完全匹配你的需求)

这个方案直接用浏览器的窗口滚动条来触发加载,彻底去掉内部滚动容器,自然就不会出现双滚动条了。

修改步骤:

  • 移除内部div的ref="iScroll"和style={{ height: "100vh", overflow: "auto"}},让列表内容自然撑开页面
  • 把滚动事件监听绑定到window对象上,记得在组件卸载时移除监听(避免内存泄漏)
  • 调整滚动触发的判断逻辑,用窗口的滚动参数来计算是否到达底部

修改后的完整代码:

class Layout extends React.Component {
  constructor(props) {
    super(props);
    this.state = { items: 30, loadingState: false };
    this.handleScroll = this.handleScroll.bind(this); // 提前绑定this
  }

  componentDidMount() {
    window.addEventListener("scroll", this.handleScroll);
  }

  componentWillUnmount() {
    window.removeEventListener("scroll", this.handleScroll); // 组件卸载时移除监听
  }

  handleScroll() {
    // 判断是否滚动到接近底部(留20px阈值避免频繁触发)
    const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
    const clientHeight = window.innerHeight || document.documentElement.clientHeight;
    const scrollHeight = document.documentElement.scrollHeight;
    
    if (scrollTop + clientHeight >= scrollHeight - 20) {
      this.loadMoreItems();
    }
  }

  displayItems() {
    var items = [];
    for (var i = 0; i < this.state.items; i++) {
      items.push(<li key={i}>Item {i}</li>);
    }
    return items;
  }

  loadMoreItems() {
    if(this.state.loadingState){
      return;
    }
    this.setState({ loadingState: true });
    setTimeout(() => {
      this.setState({ items: this.state.items + 10, loadingState: false });
    }, 1000);
  }

  render() {
    return (
      <div>
        <First />
        <div>
          <ul>{this.displayItems()}</ul>
          {this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
        </div>
      </div>
    );
  }
}

class First extends React.Component {
  render() {
    return <h1>Testing</h1>;
  }
}

ReactDOM.render(<Layout />, document.getElementById('example'));

方案二:保留内部滚动容器但解决双滚动条

如果你还是想保留内部滚动的逻辑,那需要让内部容器的高度刚好占据视口减去顶部<First>组件的高度,这样内部容器不会超出视口,窗口就不会出现额外滚动条。

修改方法:

class Layout extends React.Component {
  constructor(props) {
    super(props);
    this.state = { items: 30, loadingState: false };
    this.firstRef = React.createRef();
  }

  componentDidMount() {
    // 计算顶部组件的高度,动态设置内部容器高度
    const firstHeight = this.firstRef.current.offsetHeight;
    const iScrollElement = this.refs.iScroll;
    iScrollElement.style.height = `calc(100vh - ${firstHeight}px)`;
    
    // 原来的内部滚动监听逻辑不变
    iScrollElement.addEventListener("scroll", () => {
      if (iScrollElement.scrollTop + iScrollElement.clientHeight >= iScrollElement.scrollHeight - 20){
        this.loadMoreItems();
      }
    });
  }

  // 其余方法(displayItems、loadMoreItems)和之前一致

  render() {
    return (
      <div>
        <First ref={this.firstRef} />
        <div ref="iScroll" style={{ overflow: "auto"}}>
          <ul>{this.displayItems()}</ul>
          {this.state.loadingState ? <p className="loading"> loading More Items..</p> : ""}
        </div>
      </div>
    );
  }
}

为什么之前设height:100%会失效?

因为父级div没有设置固定高度,height:100%是相对于父元素的高度,而父元素的高度是由内容撑开的,所以内部div的高度会和列表内容高度一致,不会出现滚动条,自然无限滚动的触发条件永远不会满足。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:11:13