diff --git a/app/components/Carousel.tsx b/app/components/Carousel.tsx index aec92cb..b4fceb5 100755 --- a/app/components/Carousel.tsx +++ b/app/components/Carousel.tsx @@ -1,16 +1,23 @@ +// 引入 React 核心库 import * as React from "react"; + +// 引入 Embla Carousel 的自动播放插件 import Autoplay from "embla-carousel-autoplay"; +// 引入自定义 UI 组件:Card 和 CardContent(通常用于内容容器) import { Card, CardContent } from "@/ui/card"; + +// 引入自定义轮播组件及其子组件和类型定义 import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, - type CarouselApi, + type CarouselApi, // Embla 轮播实例的类型定义 } from "@/ui/carousel"; +// 定义轮播图使用的图片资源路径数组 const imageUrls = [ "/images/carousel-1.jpg", "/images/carousel-2.jpg", @@ -20,80 +27,122 @@ const imageUrls = [ "/images/carousel-6.jpg", ]; +// 定义组件接收的 props 接口,提供类型安全 export interface CarouselDemoProps { - paginationPosition?: 'left' | 'right'; // 默认右下角 - paginationStyle?: 'dot' | 'bar'; // 默认圆形 + // 分页指示器位置:'left' 表示左下角,'right' 表示右下角,默认为 'right' + paginationPosition?: 'left' | 'right'; + + // 分页指示器样式:'dot' 为圆形小点,'bar' 为横向小条,默认为 'dot' + paginationStyle?: 'dot' | 'bar'; } +// 导出 CarouselDemo 组件,接收两个可选 props,并设置默认值 export function CarouselDemo({ - paginationPosition = 'right', - paginationStyle = 'dot', + paginationPosition = 'right', // 默认右下角 + paginationStyle = 'dot', // 默认圆形指示器 }: CarouselDemoProps) { + // 存储 Embla 轮播实例的引用,用于控制滚动等操作 const [api, setApi] = React.useState(); + + // 当前激活的幻灯片索引(从 0 开始) const [current, setCurrent] = React.useState(0); + + // 总共的幻灯片数量(由 Embla API 动态获取) const [count, setCount] = React.useState(0); + + // 图片总数(用于渲染轮播项) const totalSlides = imageUrls.length; + // 副作用:监听 api 变化,初始化轮播状态并绑定 select 事件 React.useEffect(() => { - if (!api) return; + if (!api) return; // 如果 api 尚未就绪,直接返回 + // 获取所有 snap 点的数量(即幻灯片总数) setCount(api.scrollSnapList().length); + + // 设置当前选中的 snap 索引 setCurrent(api.selectedScrollSnap()); + // 监听轮播切换事件(用户手动滑动或自动播放时触发) api.on("select", () => { - setCurrent(api.selectedScrollSnap()); + setCurrent(api.selectedScrollSnap()); // 更新当前激活项 }); - }, [api]); + }, [api]); // 仅当 api 发生变化时重新执行 + // 渲染组件 return ( + // 外层容器:相对定位,占满父容器宽高
+ + {/* 轮播主容器 */} + {/* 轮播内容区域 */} + {/* 遍历图片数组,为每张图创建一个轮播项 */} {imageUrls.map((src, index) => ( - + + {/* 内部包裹层:无内边距,占满 */}
+ {/* 使用 CardContent 包裹图片,移除默认间距 */} + {/* 图片元素:自动填充容器,保持比例裁剪 */} {`Slide
))}
+ + {/* 上一张按钮(左箭头) */} + + {/* 下一张按钮(右箭头) */}
- {/* 分页指示器 */} + {/* 分页指示器容器:绝对定位在底部 */}
+ {/* 动态生成指示器按钮 */} {Array.from({ length: count }).map((_, index) => (
diff --git a/app/routes/news.tsx b/app/routes/news.tsx index 88ec529..28e8cff 100755 --- a/app/routes/news.tsx +++ b/app/routes/news.tsx @@ -13,6 +13,7 @@ import { MicroVision } from "@/components/news/body/FireNews/MicroVision"; import { Hotline } from "@/components/news/body/FireNews/Hotline"; import { AutoCarouselDemo } from "@/components/AutoCarousel"; import { Footer } from "@/components/news/footer/footer"; +import { CarouselDemo } from "@/components/Carousel"; export function meta( ) { return [