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

如何在React中实现带左右箭头的多图及影视网格横向滑动?

嘿,我来帮你搞定这个Netflix风格的横向滑动网格!你的两个问题本质是同一个场景,我给你两种实用的实现方案,结合你现有的代码来调整,你可以根据需求选:

方案一:手动实现(无依赖,灵活可控)

这种方式不需要引入第三方库,完全自己控制滚动逻辑,适合需要高度定制的场景。

第一步:设置基础CSS样式

先让你的.preview容器变成横向滚动的容器,同时隐藏浏览器默认的滚动条:

.collection-preview {
  position: relative;
  overflow: hidden; /* 防止箭头超出容器范围 */
}

.collection-preview .preview {
  display: flex;
  overflow-x: hidden; /* 隐藏默认横向滚动条 */
  scroll-behavior: smooth; /* 开启平滑滚动 */
  gap: 16px; /* 调整每个影视项之间的间距 */
}

/* 隐藏各浏览器的默认滚动条 */
.collection-preview .preview::-webkit-scrollbar {
  display: none;
}
.collection-preview .preview {
  -ms-overflow-style: none;  /* IE & Edge */
  scrollbar-width: none;  /* Firefox */
}

第二步:添加箭头控制逻辑

在React组件里用useRef获取滚动容器的DOM元素,然后通过scrollBy方法控制滚动,还可以监听滚动位置来禁用/启用箭头:

import { useRef, useState, useEffect } from 'react';

function CollectionPreview({ title, movies, movieData, tvshow, tvData }) {
  // 获取滚动容器的引用
  const previewRef = useRef(null);
  // 标记是否可以向左/向右滚动
  const [canScrollLeft, setCanScrollLeft] = useState(false);
  const [canScrollRight, setCanScrollRight] = useState(true);
  // 每次滚动的距离,根据你的影视项宽度调整(比如每个item宽200px,就设220包含间距)
  const scrollStep = 300;

  // 检查当前滚动位置,更新箭头状态
  const checkScrollPos = () => {
    const container = previewRef.current;
    if (!container) return;
    setCanScrollLeft(container.scrollLeft > 0);
    setCanScrollRight(container.scrollLeft + container.clientWidth < container.scrollWidth);
  };

  // 监听滚动事件,初始化时也检查一次
  useEffect(() => {
    const container = previewRef.current;
    if (!container) return;
    container.addEventListener('scroll', checkScrollPos);
    checkScrollPos();
    return () => container.removeEventListener('scroll', checkScrollPos);
  }, []);

  // 向左滚动
  const handleScrollLeft = () => {
    previewRef.current?.scrollBy({ left: -scrollStep, behavior: 'smooth' });
  };

  // 向右滚动
  const handleScrollRight = () => {
    previewRef.current?.scrollBy({ left: scrollStep, behavior: 'smooth' });
  };

  return (
    <div className="collection-preview"> 
      <h1 className="title">{title.toUpperCase()}</h1>
      {/* 左箭头按钮 */}
      <button 
        onClick={handleScrollLeft}
        disabled={!canScrollLeft}
        className="scroll-btn scroll-left"
      >
        ←
      </button>
      {/* 右箭头按钮 */}
      <button 
        onClick={handleScrollRight}
        disabled={!canScrollRight}
        className="scroll-btn scroll-right"
      >
        →
      </button>
      <div 
        className="preview"
        ref={previewRef}
      > 
        { movies ? (movieData.map(({id, ...otherProps}) => <CollectionItem key={id} {...otherProps} />)) : null } 
        { tvshow ? (tvData.map(({id, ...otherProps}) => <CollectionItem key={id} {...otherProps} />)) : null } 
      </div> 
    </div>
  );
}

第三步:给箭头按钮加样式

让箭头固定在容器左右,样式更贴近Netflix的效果:

.scroll-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(0, 0, 0, 0.7);
  color: white;
  border: none;
  padding: 12px 8px;
  cursor: pointer;
  z-index: 10;
  font-size: 1.2rem;
  transition: opacity 0.2s;
}

.scroll-left {
  left: 0;
}

.scroll-right {
  right: 0;
}

/* 禁用时的样式 */
.scroll-btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

方案二:用第三方库快速实现(省心省力)

如果不想自己写滚动逻辑,可以用react-horizontal-scrolling-menu这个专门的库,它已经封装好了横向滚动、箭头控制、可见性判断等功能,适合快速开发。

第一步:安装库

npm install react-horizontal-scrolling-menu
# 或者用yarn
yarn add react-horizontal-scrolling-menu

第二步:修改你的组件

import { ScrollMenu, VisibilityContext } from 'react-horizontal-scrolling-menu';
import 'react-horizontal-scrolling-menu/dist/styles.css';

// 自定义箭头组件
const ScrollArrow = ({ children, onClick, disabled }) => (
  <button
    onClick={onClick}
    disabled={disabled}
    style={{
      position: 'absolute',
      top: '50%',
      transform: 'translateY(-50%)',
      background: 'rgba(0,0,0,0.7)',
      color: 'white',
      border: 'none',
      padding: '12px 8px',
      cursor: disabled ? 'not-allowed' : 'pointer',
      zIndex: 10,
      fontSize: '1.2rem',
      opacity: disabled ? 0.3 : 1
    }}
  >
    {children}
  </button>
);

// 左箭头
const LeftArrow = () => {
  const { isFirstItemVisible, scrollPrev } = useContext(VisibilityContext);
  return (
    <ScrollArrow onClick={() => scrollPrev()} disabled={isFirstItemVisible}>
      ←
    </ScrollArrow>
  );
};

// 右箭头
const RightArrow = () => {
  const { isLastItemVisible, scrollNext } = useContext(VisibilityContext);
  return (
    <ScrollArrow onClick={() => scrollNext()} disabled={isLastItemVisible}>
      →
    </ScrollArrow>
  );
};

function CollectionPreview({ title, movies, movieData, tvshow, tvData }) {
  // 合并影视项数组
  const items = [];
  if (movies) {
    items.push(...movieData.map(({ id, ...props }) => <CollectionItem key={id} {...props} />));
  }
  if (tvshow) {
    items.push(...tvData.map(({ id, ...props }) => <CollectionItem key={id} {...props} />));
  }

  return (
    <div className="collection-preview"> 
      <h1 className="title">{title.toUpperCase()}</h1>
      <ScrollMenu 
        LeftArrow={LeftArrow} 
        RightArrow={RightArrow}
        style={{ gap: '16px', overflow: 'hidden' }}
      >
        {items}
      </ScrollMenu>
    </div>
  );
}

两种方案对比

  • 手动实现:完全可控,不需要依赖第三方包,适合需要定制滚动速度、动画效果或者特殊交互的场景。
  • 第三方库:代码量少,不用自己处理滚动细节,适合快速开发,风格统一。

根据你的需求选就行,两种方案都能实现你要的Netflix式横向滑动网格~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:14:19