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
相关产品推荐
相关产品推荐

