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

Vue.js实现类Netflix电影滑动轮播组件技术求助

Vue3 + TypeScript 实现Netflix风格横向影片轮播

方案一:使用Swiper 8+适配Vue3

Swiper 8及以上版本原生支持Vue3,之前失败大概率是版本或配置问题,按以下步骤操作:

1. 安装依赖

npm install swiper
# 或yarn
yarn add swiper

2. 组件实现代码

<template>
  <div class="movie-carousel">
    <h3 class="carousel-title">{{ title }}</h3>
    <swiper
      :slides-per-view="auto"
      :space-between="16"
      :allow-touch-move="true"
      :navigation="{
        nextEl: '.swiper-btn-next',
        prevEl: '.swiper-btn-prev'
      }"
      class="swiper-container"
    >
      <swiper-slide v-for="movie in movies" :key="movie.id">
        <div class="movie-card">
          <img :src="movie.posterUrl" :alt="movie.title" class="movie-poster" />
          <p class="movie-name">{{ movie.title }}</p>
        </div>
      </swiper-slide>
      <!-- 导航按钮 -->
      <div class="swiper-btn-prev"></div>
      <div class="swiper-btn-next"></div>
    </swiper>
  </div>
</template>

<script setup lang="ts">
import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/css';
import 'swiper/css/navigation';

interface Movie {
  id: string;
  title: string;
  posterUrl: string;
}

const props = defineProps<{
  title: string;
  movies: Movie[];
}>();
</script>

<style scoped>
.movie-carousel {
  margin: 20px 0;
}
.carousel-title {
  color: #fff;
  margin-bottom: 12px;
  font-size: 18px;
}
.swiper-container {
  height: auto;
  padding-bottom: 10px;
}
.movie-card {
  width: 180px;
  cursor: pointer;
}
.movie-poster {
  width: 100%;
  border-radius: 4px;
  transition: transform 0.3s;
}
.movie-card:hover .movie-poster {
  transform: scale(1.05);
}
.movie-name {
  color: #fff;
  font-size: 14px;
  margin-top: 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 自定义导航按钮样式 */
.swiper-btn-prev, .swiper-btn-next {
  color: #fff;
  width: 40px;
  height: 40px;
  background: rgba(0,0,0,0.5);
  border-radius: 50%;
  top: 50%;
  transform: translateY(-50%);
}
.swiper-btn-prev::after, .swiper-btn-next::after {
  font-size: 18px;
}
</style>

关键配置说明

  • slides-per-view="auto":让Swiper自动根据容器宽度适配显示的影片数量
  • space-between="16":设置影片卡片之间的间距
  • allow-touch-move="true":开启触摸滑动支持
  • 导航按钮:自定义样式贴合Netflix风格,hover时显示,增强交互

方案二:纯手写实现(无第三方库)

如果不想依赖Swiper,可通过原生CSS+Vue3事件实现:

<template>
  <div class="carousel-wrapper">
    <h3 class="carousel-title">{{ title }}</h3>
    <div class="carousel-container" ref="carouselRef">
      <button class="scroll-btn scroll-left" @click="scrollLeft">‹</button>
      <div class="movie-list">
        <div class="movie-card" v-for="movie in movies" :key="movie.id">
          <img :src="movie.posterUrl" :alt="movie.title" class="movie-poster" />
          <p class="movie-name">{{ movie.title }}</p>
        </div>
      </div>
      <button class="scroll-btn scroll-right" @click="scrollRight">›</button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

interface Movie {
  id: string;
  title: string;
  posterUrl: string;
}

const props = defineProps<{
  title: string;
  movies: Movie[];
}>();

const carouselRef = ref<HTMLElement | null>(null);
const scrollStep = 300; // 每次滚动的距离

const scrollLeft = () => {
  carouselRef.value?.scrollBy({ left: -scrollStep, behavior: 'smooth' });
};

const scrollRight = () => {
  carouselRef.value?.scrollBy({ left: scrollStep, behavior: 'smooth' });
};
</script>

<style scoped>
.carousel-wrapper {
  margin: 20px 0;
}
.carousel-title {
  color: #fff;
  margin-bottom: 12px;
  font-size: 18px;
}
.carousel-container {
  position: relative;
  overflow-x: hidden;
}
.movie-list {
  display: flex;
  gap: 16px;
  padding: 10px 0;
  overflow-x: auto;
  scroll-behavior: smooth;
  /* 隐藏滚动条 */
  scrollbar-width: none;
}
.movie-list::-webkit-scrollbar {
  display: none;
}
.movie-card {
  width: 180px;
  flex-shrink: 0;
  cursor: pointer;
}
.movie-poster {
  width: 100%;
  border-radius: 4px;
  transition: transform 0.3s;
}
.movie-card:hover .movie-poster {
  transform: scale(1.05);
}
.movie-name {
  color: #fff;
  font-size: 14px;
  margin-top: 8px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.scroll-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,0.7);
  color: #fff;
  font-size: 20px;
  cursor: pointer;
  z-index: 10;
  opacity: 0;
  transition: opacity 0.3s;
}
.carousel-container:hover .scroll-btn {
  opacity: 1;
}
.scroll-left {
  left: 10px;
}
.scroll-right {
  right: 10px;
}
</style>

核心实现逻辑

  • 用overflow-x: auto实现横向滚动容器,隐藏原生滚动条
  • 通过scrollBy方法结合平滑滚动实现按钮控制
  • 触摸滑动由浏览器原生支持,无需额外处理
  • 按钮hover显示,贴合Netflix交互风格

常见问题排查

  1. Swiper无效:确认安装的是Swiper 8+版本,且导入的是swiper/vue而非旧版依赖
  2. vue2-touch-events不生效:该库仅支持Vue2,Vue3需使用原生触摸事件或Swiper的触摸支持
  3. 滚动不流畅:确保影片卡片设置flex-shrink: 0,避免被压缩

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 14:44:55