如何实现React卡片横向滚动效果?求助解决方案
实现React卡片横向滚动(无第三方库)
问题分析
你当前通过切换currentPage切片数据的方式,本质是直接替换显示的卡片集合,无法实现滚动过渡效果。之前编写的CSS类未在组件中正确绑定,且手动为每个卡片写transform规则的方式扩展性极差,卡片数量变化时需要大量修改代码,这是导致方案失效的核心原因。
解决方案
采用容器原生滚动+平滑过渡的方案,无需第三方库,核心思路:
- 容器内渲染完整卡片列表,不做数据切片
- 通过操作容器的
scrollLeft属性控制横向滚动 - 配合CSS的
scroll-behavior: smooth实现平滑动画 - 按钮控制滚动步长(每次滚动6张卡片的宽度+间距)
步骤1:修改Home组件代码
/* eslint-disable react/prop-types */ import { useState, useRef } from "react"; import { Input } from "./ui/input"; import Button from "./ui/button"; import VoiceCard from "./voicecard"; import data from "../lib/dummydata" import { debounce } from "lodash"; import { ChevronRight, ChevronLeft } from "lucide-react"; const Home = () => { const cardContainerRef = useRef(null); // 单张卡片总宽度:卡片宽度(w-40=160px) + 间距(space-x-3=12px),可根据实际样式调整 const cardTotalWidth = 172; const [canScrollLeft, setCanScrollLeft] = useState(false); const [canScrollRight, setCanScrollRight] = useState(true); // 监听滚动状态,更新按钮禁用状态 const handleScroll = () => { const container = cardContainerRef.current; if (!container) return; setCanScrollLeft(container.scrollLeft > 0); setCanScrollRight(container.scrollLeft < container.scrollWidth - container.clientWidth); }; // 滚动下一组卡片 const handleNextPage = debounce(() => { cardContainerRef.current?.scrollBy({ left: cardTotalWidth * 6, behavior: "smooth" }); }, 600); // 滚动上一组卡片 const handlePrevPage = debounce(() => { cardContainerRef.current?.scrollBy({ left: -cardTotalWidth * 6, behavior: "smooth" }); }, 400); return ( <div className="flex justify-center w-screen"> <div id="home-container" className="grad-background flex flex-col justify-center items-center"> <div id="top-text" className="flex flex-col items-center pb-4"> <span>⭐ ⭐ ⭐ ⭐</span> <h2 className="font-semibold">stuff</h2> </div> <div id="main-text" className="text-center"> <h1 className="font-semibold">stuff </h1> </div> <div id="bottom-text" className="pt-4"> <h2 className="font-semibold" id="biline">stuff</h2> </div> <div id="search-bar" className="pt-3 w-full flex flex-col items-center"> <div className="landing-search flex"> <Input placeholder="Sök efter röster" /> <Button id="search-button"></Button> </div> <div id="start-button" className="pt-7"> <Button>Starta nu</Button> </div> </div> <div id="button-container" className="flex space-x-1 items-center ml-auto pt-8"> <div id="trending-text" className=""> <h3 className="font-semibold pl-">stuff</h3> </div> <button onClick={handlePrevPage} disabled={!canScrollLeft} className="bg-white rounded-full w-30 h-15 border-2 border-gray-200 "> <ChevronLeft /> </button> <button onClick={handleNextPage} disabled={!canScrollRight} className="bg-white rounded-full w-30 h-15 border-2 border-gray-200 "> <ChevronRight/> </button> <Button variant="outline">Visa alla</Button> </div> {/* 修改后的卡片容器 */} <div ref={cardContainerRef} id="card-container" className="flex space-x-3 overflow-x-auto scroll-smooth pb-4" onScroll={handleScroll} style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }} > {data.map((card) => <VoiceCard key={card.id} img={card.img} name={card.name} /> )} </div> </div> </div> ); } export default Home;
步骤2:隐藏滚动条(可选)
如果需要隐藏默认横向滚动条,在全局CSS中添加:
#card-container::-webkit-scrollbar { display: none; }
关键改动说明
- 使用
useRef获取容器DOM,直接调用scrollBy方法控制滚动 - 移除数据切片逻辑,容器内渲染全部卡片,自然横向排列
- 通过
scroll-behavior: smooth实现原生平滑滚动动画 - 监听容器滚动事件,动态判断按钮是否可点击,替代原分页逻辑
- 计算单张卡片总宽度作为滚动步长,适配不同数量的卡片滚动需求
内容的提问来源于stack exchange,提问作者anon
相关产品推荐
相关产品推荐

