shadcn-svelte Carousel 组件完整实战指南:基于 Embla 的触摸滑动轮播
shadcn-svelte Carousel 组件完整实战指南基于 Embla 的触摸滑动轮播【免费下载链接】shadcn-svelteshadcn/ui, but for Svelte. ✨项目地址: https://gitcode.com/GitHub_Trending/sh/shadcn-svelteCarousel 是 shadcn-svelte 提供的高质量轮播组件底层基于 Embla Carousel 构建原生支持触摸滑动、键盘操作与无障碍语义。本文以 docs/content/components/carousel.md 文档为骨架结合仓库内 组件源码 与 示例代码系统讲解其安装、基础用法、尺寸/间距/方向控制、选项配置、API 调用、事件监听与插件扩展帮助你在 Svelte 5 项目中快速落地一个可缩放、可定制、可无障碍访问的轮播。AboutCarousel 组件是什么shadcn-svelte 的 Carousel 组件完全构建在 Embla Carousel 库之上。这意味着你不需要自己实现滑动逻辑、快照对齐或触摸手势而是通过一个轻量封装把 Embla 的能力以 shadcn 风格的声明式组件 API 暴露出来。从源码结构看组件由五个子组件组成index.tsCarousel.Root整体容器负责初始化 Embla 实例、维护共享状态carousel.svelteCarousel.Content滚动视口与滑动轨道carousel-content.svelteCarousel.Item单个轮播项carousel-item.svelteCarousel.Previous/Carousel.Next上/下一个箭头按钮carousel-previous.svelte、carousel-next.svelte组件之间通过 Svelte 的 Context API 通信Root调用setEmblaContext写入共享状态其余子组件通过getEmblaContext读取见 context.ts。如果子组件被用在Root之外会抛出must be used within a Carousel.Root component错误。安装推荐使用 shadcn-svelte CLI 安装它会自动处理好组件代码与依赖npx shadcn-sveltelatest add carousel也可以手动安装先安装 Embla 的 Svelte 绑定作为依赖docs 项目使用embla-carousel-svelte^8.6.0见 docs/package.jsonnpm install embla-carousel-svelte -D然后把 carousel 目录 下的 7 个文件carousel.svelte、carousel-content.svelte、carousel-item.svelte、carousel-previous.svelte、carousel-next.svelte、context.ts、index.ts复制到项目的$lib/components/ui/carousel/下。如果你还要使用自动播放插件额外安装embla-carousel-autoplay文档项目版本为^8.6.0见 docs/package.json。基础用法组件采用 shadcn 经典的“命名空间导入”模式script langts import * as Carousel from $lib/components/ui/carousel/index.js; /script最小可用结构如下——一个Root包裹若干个ItemContent是滑动容器Previous/Next是前后翻页按钮Carousel.Root Carousel.Content Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item /Carousel.Content Carousel.Previous / Carousel.Next / /Carousel.Root从源码看各子组件已经内置了必要的无障碍与布局语义Root渲染为roleregionaria-roledescriptioncarousel支持键盘左右方向键控制carousel.svelteContent外层视口overflow-hidden内层轨道使用 flex 布局水平方向为-ms-4的负边距用于抵消每个 item 的ps-4内边距carousel-content.svelteItem渲染为rolegrouparia-roledescriptionslide默认basis-full即一次显示一张水平方向自带ps-4间距carousel-item.sveltePrevious/Next是基于Button的图标按钮根据canScrollPrev/canScrollNext自动设置disabled与aria-disabled内置sr-only文本carousel-previous.svelte控制轮播项尺寸Sizes默认每个Item占满整个视口basis-full。要一次展示多张只需在Item上覆盖basis工具类!-- 每个 item 占轮播宽度的 33%。 -- Carousel.Root Carousel.Content Carousel.Item classbasis-1/3.../Carousel.Item Carousel.Item classbasis-1/3.../Carousel.Item Carousel.Item classbasis-1/3.../Carousel.Item /Carousel.Content /Carousel.Root也支持响应式断点组合例如小屏显示 50%、大屏显示 33%Carousel.Root Carousel.Content Carousel.Item classmd:basis-1/2 lg:basis-1/3.../Carousel.Item Carousel.Item classmd:basis-1/2 lg:basis-1/3.../Carousel.Item Carousel.Item classmd:basis-1/2 lg:basis-1/3.../Carousel.Item /Carousel.Content /Carousel.Root仓库示例 carousel-size.svelte 中同时配合opts{{ align: start }}让第一张卡片从视口左侧对齐开始展示。实现上Item 的默认样式basis-full位于cn()合并的最前面因此你的basis-*类会正确覆盖它carousel-item.svelte。控制轮播项间距Spacing间距由“正负配对”实现在Item上使用ps-[VALUE]设置左侧内边距在Content上使用负的-ms-[VALUE]抵消首项保证首项与视口边缘对齐、各项间距一致Carousel.Root Carousel.Content class-ms-4 Carousel.Item classps-4.../Carousel.Item Carousel.Item classps-4.../Carousel.Item Carousel.Item classps-4.../Carousel.Item /Carousel.Content /Carousel.Root同样的技巧可以做成响应式间距Carousel.Root Carousel.Content class-ms-2 md:-ms-4 Carousel.Item classps-2 md:ps-4.../Carousel.Item Carousel.Item classps-2 md:ps-4.../Carousel.Item Carousel.Item classps-2 md:ps-4.../Carousel.Item /Carousel.Content /Carousel.Root之所以需要负边距是因为 carousel-content.svelte 的轨道本身已经自带水平-ms-4或垂直-mt-4默认负边距来配对 Item 的默认ps-4或pt-4内边距。当你自定义间距时cn()合并顺序保证传入的类会覆盖默认值因此一定要成对修改Item的ps-*与Content的-ms-*数值必须一致。设置轮播方向Orientation通过orientationprop 切换水平/垂直轮播Carousel.Root orientationvertical | horizontal Carousel.Content Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item /Carousel.Content /Carousel.Root默认值为horizontal。从实现细节看orientation会被传入共享 context随后影响三处渲染context.tsContent将 Embla 的axis设置为x或y并把轨道布局切换为-ms-4水平或-mt-4 flex-col垂直carousel-content.svelteItem的间距从ps-4切换为pt-4carousel-item.sveltePrevious/Next按钮的定位从左右居中切换为上下居中并旋转 90°carousel-previous.svelte完整示例见 carousel-orientation.svelte垂直轮播通常还要给Content设置固定高度如h-[200px]并配合opts{{ align: start }}。选项配置OptionsEmbla 的全部选项都可以通过optsprop 传入Carousel.Root opts{{ align: start, loop: true, }} Carousel.Content Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item /Carousel.Content /Carousel.RootCarouselOptions类型直接派生自embla-carousel-svelte的 options 类型context.ts所以 Embla 文档中的align、loop、startIndex、dragFree、containScroll、slidesToScroll等选项都可以直接使用。Root默认opts {}Content在初始化 Embla 时会把共享 options 与内部固定的容器选择器合并carousel-content.svelte。通过 API 读取轮播状态如果你需要知道“当前在第几张”可以通过setApi回调拿到 Embla 实例配合 Svelte 5 的$state/$derived/$effect保持 UI 与轮播同步script langts import { type CarouselAPI } from $lib/components/ui/carousel/context.js; import * as Carousel from $lib/components/ui/carousel/index.js; let api $stateCarouselAPI(); let current $state(0); const count $derived(api ? api.scrollSnapList().length : 0); $effect(() { if (api) { current api.selectedScrollSnap() 1; api.on(select, () { current api!.selectedScrollSnap() 1; }); } }); /script Carousel.Root setApi{(emblaApi) (api emblaApi)} Carousel.Content Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item /Carousel.Content /Carousel.Root这段逻辑可以直接从 carousel-api.svelte 示例中验证api.scrollSnapList().length得到总页数api.selectedScrollSnap()得到当前索引api.on(select, ...)在每次切换后更新current最终在轮播下方渲染Slide {current} of {count}。从源码看setApi由Root在 Embla 的onInit事件中调用carousel.svelte同一时刻还会初始化scrollSnaps与selectedIndex并注册select监听组件卸载时通过$effect清理监听避免内存泄漏carousel.svelte。CarouselAPI类型通过on:emblaInit事件的载荷推断而来context.ts。事件监听Events事件监听与读取 API 是同一条路径先通过setApi拿到实例再在$effect里注册监听script langts import { type CarouselAPI } from $lib/components/ui/carousel/context.js; import * as Carousel from $lib/components/ui/carousel/index.js; let api $stateCarouselAPI(); $effect(() { if (api) { api.on(select, () { // do something }); } }); /script Carousel.Root setApi{(emblaApi) (api emblaApi)} Carousel.Content Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item Carousel.Item.../Carousel.Item /Carousel.Content /Carousel.RootEmbla 的事件命名沿用其自身的约定select只是其中之一init、reInit、slidesChanged、pointerDown、settle、scroll等都可以按需监听。注意setApi与onInit只在 Embla 实例初始化时触发一次所以把api.on(...)放进$effect依赖api变化是最可靠的做法——这与仓库内部在onInit中注册onSelect的写法carousel.svelte是一致的。插件扩展Pluginspluginsprop 接收一个 Embla 插件数组。最常见的场景是自动播放需要先安装插件包npm install embla-carousel-autoplay -D然后在脚本中创建插件实例并传入script langts import Autoplay from embla-carousel-autoplay; import * as Carousel from $lib/components/ui/carousel/index.js; /script Carousel.Root plugins{[ Autoplay({ delay: 2000, }), ]} !-- ... -- /Carousel.Root仓库示例 carousel-plugin.svelte 演示了一个更完整的模式把Autoplay实例保存在变量里delay: 2000设置每 2 秒自动切换stopOnInteraction: true让用户滑动或点击后自动停止再通过onmouseenter{plugin.stop}和onmouseleave{plugin.reset}实现“悬停暂停、离开继续”的体验。CarouselPlugins类型同样派生自 Embla 的插件类型context.tsContent会把插件原样传给 Embla 初始化carousel-content.svelte。小结shadcn-svelte 的 Carousel 把 Embla Carousel 的能力封装成了符合 shadcn 习惯的组件 API五个子组件各司其职Context 负责状态共享opts/plugins透传 Embla 的选项与插件setApi则让你完全掌握底层实例。无论是一张一张翻页、多张同屏、响应式尺寸、自定义间距、垂直滚动还是自动播放与状态同步都能在几行 Svelte 代码内完成。进一步探索可以阅读 carousel 组件源码目录 与 carousel 示例目录以及 Embla Carousel 官方文档中关于 options 与 plugins 的更多细节。【免费下载链接】shadcn-svelteshadcn/ui, but for Svelte. ✨项目地址: https://gitcode.com/GitHub_Trending/sh/shadcn-svelte创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考