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

Svelte Carousel导航点激活状态随幻灯片切换异常问题

问题分析与修复方案

核心问题

  1. 轮询监听逻辑低效且易出错:无间隔的轮询会占用不必要的性能,且注册scroll事件的时机逻辑存在漏洞。
  2. 激活状态获取错误:slidesInView()[1]无法准确获取当前激活的幻灯片索引,尤其是开启loop模式后,可见幻灯片数组的索引逻辑会混乱。
  3. 状态同步不一致:点击导航点时手动设置activeCarouselItemId,未与carousel的实际滚动状态同步,导致后续状态更新失效。

修复后的代码

<script lang="ts">
  import * as Card from "$lib/components/ui/card/index.js";
  import type { CarouselAPI } from "$lib/components/ui/carousel/context";
  import * as Carousel from "$lib/components/ui/carousel/index.js";
  import { projects } from "../data/slides";
  import { MoveRight } from "lucide-svelte";

  let carouselApi: CarouselAPI;
  let activeCarouselItemId = 0;

  // 响应式监听carouselApi,自动绑定/解绑滚动事件
  $: if (carouselApi) {
    carouselApi.off("scroll", handleScroll);
    carouselApi.on("scroll", handleScroll);
    // 初始化时同步一次状态
    handleScroll(carouselApi);
  }

  function handleScroll(api: CarouselAPI) {
    // 获取当前选中的滚动点,loop模式下自动归一化索引
    const snapIndex = api.selectedScrollSnap();
    activeCarouselItemId = snapIndex % projects.length;
  }

  function setActiveCarouselItem(index: number) {
    // 归一化索引,适配loop模式的滚动逻辑
    const normalizedIndex = carouselApi?.normalizeScrollSnap(index) ?? index;
    carouselApi?.scrollTo(normalizedIndex);
  }
</script>

<Carousel.Root
  opts={{
    loop: true,
  }}
  class="w-full bg-black"
  bind:api={carouselApi}
>
  <Carousel.Content class="">
    {#each projects as project}
      <Carousel.Item class="basis-1/2 hover:cursor-grab border-none">
        <div class="my-4 border-none">
          <Card.Root class="border-none">
            <Card.Content
              class="flex h-[60vh] p-6 rounded-lg border-none"
              style="background-image: url({project.image}); background-repeat: no-repeat; background-size: cover;"
            >
              <div class="absolute top-12 left-12 h-full text-white uppercase">
                <h2 class="text-2xl font-semibold">{project.title}</h2>
                <p class="text-xl font-normal">{project.description}</p>
                <button
                  class="flex items-center gap-2 absolute bottom-24 left-0 uppercase font-black text-xl tracking-wider border-2 rounded-full py-2 px-6 hover:bg-white/50 ease-in-out duration-300"
                >Explore <MoveRight size="40" /></button>
              </div>
            </Card.Content>
          </Card.Root>
        </div>
      </Carousel.Item>
    {/each}
  </Carousel.Content>
</Carousel.Root>

<!-- Progress circles -->
<div class="flex space-x-2 bg-black w-full items-center justify-center py-12">
  {#each projects as item, idx}
    <button
      on:click={() => setActiveCarouselItem(idx)}
      class="rounded-full aspect-square w-4 {idx === activeCarouselItemId ? 'bg-white' : 'bg-white/30'}"
      aria-label={`Go to slide ${idx + 1}`}
    ></button>
  {/each}
</div>

关键修复点

  • 替换轮询为响应式监听:用Svelte的$:响应式语句监听carouselApi变化,自动注册/移除scroll事件,避免无意义的性能消耗。
  • 正确获取激活索引:使用api.selectedScrollSnap()获取当前选中的滚动点索引,配合% projects.length适配loop模式下的索引循环逻辑。
  • 统一状态更新逻辑:点击导航点仅触发滚动操作,激活状态完全由carousel的scroll事件同步,确保状态与实际幻灯片位置一致。
  • 归一化滚动索引:调用scrollTo前用normalizeScrollSnap处理索引,避免loop模式下出现滚动位置异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:29:57