Svelte实现滚动到底部自动调用fetchMore加载更多内容方案
解决Svelte滚动到底部加载更多帖子的问题
看起来你当前的滚动位置判断逻辑有点问题——只比较clientHeight和scrollY是不够的,这两个值分别对应内容容器的可见高度和窗口的滚动距离,没法准确判断是否已经滚动到页面底部。下面我来帮你修正这个逻辑,同时优化请求避免重复加载。
问题分析
你现在的checkScrollPosition函数只做了clientHeight <= y的判断,这显然不准确:
y(即scrollY)是窗口顶部到文档顶部的滚动距离clientHeight是你绑定的内容容器的可见高度
这两个值的对比根本无法反映窗口底部是否接近文档底部。
解决方案
1. 修正滚动位置判断逻辑(全局窗口滚动场景)
如果你的页面是整个窗口滚动,我们需要结合文档总高度、窗口可见高度和当前滚动位置来判断:
let isLoading = false; // 新增:防止重复请求 const checkScrollPosition = () => { // 获取文档的总高度 const documentHeight = document.documentElement.scrollHeight; // 获取窗口的可见高度 const windowHeight = window.innerHeight; // 计算窗口底部的位置(滚动距离 + 窗口高度) const scrollBottom = y + windowHeight; // 当窗口底部距离文档底部小于200px时触发加载(可根据需求调整阈值) // 同时要判断是否还有下一页、是否正在加载,避免无效请求 if (scrollBottom >= documentHeight - 200 && pageInfo?.hasNextPage && !isLoading) { fetchMore(); } };
2. 优化fetchMore函数,避免重复请求
给fetchMore加上加载状态锁,防止滚动时多次触发请求:
const fetchMore = async () => { if (isLoading) return; // 如果正在加载,直接返回 isLoading = true; try { await posts.fetchMore({ variables: { first, after }, updateQuery: (previousResult, { fetchMoreResult }) => { const newEdges = fetchMoreResult.getPosts.edges; const newPageInfo = fetchMoreResult.getPosts.pageInfo; // 更新全局的pageInfo和after pageInfo = newPageInfo; after = newPageInfo.endCursor; return newEdges.length ? { getPosts: { __typename: previousResult.getPosts.__typename, edges: [...previousResult.getPosts.edges, ...newEdges], pageInfo: newPageInfo } } : previousResult; } }); } catch (error) { console.error('加载更多帖子失败:', error); } finally { isLoading = false; // 请求结束后解锁 } };
3. 如果是容器内滚动(可选)
如果你的帖子列表是在某个带滚动条的容器内(而非全局窗口滚动),那需要调整为监听容器的滚动事件,并用容器自身的属性判断:
首先给内容容器绑定引用:
<div slot="body" bind:this={scrollContainer} on:scroll={checkScrollPosition}>
然后修改脚本部分:
let scrollContainer; let isLoading = false; const checkScrollPosition = () => { if (!scrollContainer) return; const { scrollTop, clientHeight, scrollHeight } = scrollContainer; // 容器滚动到底部的判断逻辑 if (scrollTop + clientHeight >= scrollHeight - 200 && pageInfo?.hasNextPage && !isLoading) { fetchMore(); } };
这时候可以移除 <svelte:window on:scroll={checkScrollPosition} bind:scrollY={y} />,因为我们现在监听的是容器的滚动事件。
额外注意点
- 阈值(200px)可以根据你的需求调整,设置一个提前量能让用户在滚动到底部前就开始加载,提升体验
- 确保
pageInfo正确更新,这样hasNextPage的判断才会生效,避免在没有更多数据时继续请求
内容的提问来源于stack exchange,提问作者poku17
相关产品推荐
相关产品推荐

