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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 18:32:31