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

