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

如何实现React卡片横向滚动效果?求助解决方案

实现React卡片横向滚动(无第三方库)

问题分析

你当前通过切换currentPage切片数据的方式,本质是直接替换显示的卡片集合,无法实现滚动过渡效果。之前编写的CSS类未在组件中正确绑定,且手动为每个卡片写transform规则的方式扩展性极差,卡片数量变化时需要大量修改代码,这是导致方案失效的核心原因。

解决方案

采用容器原生滚动+平滑过渡的方案,无需第三方库,核心思路:

  1. 容器内渲染完整卡片列表,不做数据切片
  2. 通过操作容器的scrollLeft属性控制横向滚动
  3. 配合CSS的scroll-behavior: smooth实现平滑动画
  4. 按钮控制滚动步长(每次滚动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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 07:34:57