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

Svelte实现无限滚动添加新元素时出现闪烁问题求助

问题分析与修复方案

你的Svelte无限滚动出现闪烁、重复显示旧元素的问题,主要由数据更新逻辑不严谨、Scroll Snap强制对齐、图片加载导致容器高度变化这三个核心原因引发,以下是针对性的修复步骤:


1. 修正数据更新逻辑,避免重复添加与错误触发加载

当前代码中newBatch作为中间变量的响应式更新逻辑存在漏洞,且hasMore的判断条件错误,会导致重复触发请求或重复添加数据。

修复后的App.svelte脚本部分

<script>
    import { onMount } from 'svelte';
    import InfiniteScroll from './InfiniteScroll.svelte';
    
    let page = 1;
    let data = [];
    let isLoading = false;
    // 根据API返回数量判断是否还有更多数据(示例中每页返回2条)
    let hasMore = true;
    
    async function fetchData() {
        // 防止重复触发请求
        if (isLoading || !hasMore) return;
        isLoading = true;
        
        const response = await fetch(`https://picsum.photos/v2/list?page=${page}&limit=2`);
        const newBatch = await response.json();
        
        // 更新数据与分页状态
        hasMore = newBatch.length === 2;
        data = [...data, ...newBatch];
        page++;
        isLoading = false;
    };
    
    onMount(fetchData);
</script>

同步修改InfiniteScroll组件的属性

<InfiniteScroll
  hasMore={hasMore}
  threshold={100}
  on:loadMore={fetchData}
/>

2. 调整Scroll Snap规则,避免强制滚动对齐

原代码中scroll-snap-type: y mandatory会在容器高度变化时强制滚动到最近的对齐点,引发视觉跳动。将其改为proximity,仅在滚动接近对齐点时触发对齐:

.parent {
    max-height: 100vh;
    overflow-y: auto;
    scroll-snap-type: y proximity; /* 替换原有的mandatory */
    margin: 0 auto;
}

3. 固定图片尺寸,避免加载时容器高度变化

图片未设置宽高会导致加载过程中容器高度波动,引发滚动位置跳动,给图片添加固定尺寸与适配规则:

.cover {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    object-fit: cover; /* 保持图片比例并覆盖容器 */
}

4. 修复InfiniteScroll组件的事件监听问题

原组件的响应式语句会重复添加滚动监听,导致多次触发加载逻辑,改为在onMount中一次性添加监听:

修复后的InfiniteScroll.svelte脚本部分

<script>
  import { onMount, onDestroy, createEventDispatcher } from "svelte";

  export let threshold = 0;
  export let horizontal = false;
  export let elementScroll;
  export let hasMore = true;

  const dispatch = createEventDispatcher();
  let isLoadMore = false;
  let component;
  let scrollElement;

  onMount(() => {
    scrollElement = elementScroll || component.parentNode;
    scrollElement.addEventListener("scroll", onScroll);
    scrollElement.addEventListener("resize", onScroll);
  });

  const onScroll = e => {
    const element = scrollElement;

    const offset = horizontal
      ? element.scrollWidth - element.clientWidth - element.scrollLeft
      : element.scrollHeight - element.clientHeight - element.scrollTop;

    if (offset <= threshold) {
      if (!isLoadMore && hasMore) {
        dispatch("loadMore");
      }
      isLoadMore = true;
    } else {
      isLoadMore = false;
    }
  };

  onDestroy(() => {
    if (scrollElement) {
      scrollElement.removeEventListener("scroll", onScroll);
      scrollElement.removeEventListener("resize", onScroll);
    }
  });
</script>

<div bind:this={component} style="width:0px" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:00:59