Vue3 + Swiper.js 实现无缝轮播图组件

Vue3 + Swiper.js 实现无缝轮播图组件

前言

在数据可视化大屏项目中,轮播图组件是一个常见的需求。本文将详细介绍如何使用 Vue3 和 Swiper.js 开发一个功能完善的无缝轮播图组件,并分享实际项目中的最佳实践。

技术栈

  • Vue 3 (Composition API)
  • TypeScript
  • Swiper.js
  • CSS3

组件概述

SeamlessCarousel 是一个基于 Swiper.js 的 Vue 3 轮播图组件,专门用于展示虚拟电厂信息。该组件支持自动播放、手动导航、响应式布局等功能,适用于数据可视化大屏展示。

组件功能预览

我们即将开发的轮播图组件具备以下功能:

✅ 自动播放与手动切换

✅ 中心突出显示效果

✅ 响应式布局

✅ 详细信息展示

✅ 导航按钮

✅ 数据绑定

步骤一:创建项目并安装依赖

复制代码
npm install swiper
npm install -D @types/swiper  # 如果使用TypeScript

步骤二:创建组件

  • 创建一个名为SeamlessCarousel.vue 的组件文件,并定义组件的属性、数据、方法、事件等。
vue 复制代码
<template>
  <div class="seamless-carousel-container">
    <div class="carousel-wrapper">
      <!-- 主轮播 -->
      <swiper
        ref="mainSwiperRef"
        :preload-classes="true"
        :lazy="true"
        :initial-slide="0"
        :modules="modules"
        :space-between="180"
        :slides-per-view="3"
        :centered-slides="true"
        :loop="true"
        :loop-additional-slides="1"
        :grab-cursor="true"
        :effect="'slide'"
        :speed="800"
        :allow-touch-move="true"
        :watch-slides-progress="true"
        :watch-slides-visibility="true"
        :autoplay="{
          delay: 3000,
          disableOnInteraction: true,
          pauseOnMouseEnter: true,
          waitForTransition: false,
        }"
        
        :navigation="{
          nextEl: '.right-arrow',
          prevEl: '.left-arrow',
        }"
      
        class="main-swiper"
        @swiper="setMainSwiper"
        @slide-change="onSlideChange"
      >
        <swiper-slide v-for="(plant, index) in slides" :key="index">
          <div class="test-plant-card" :class="{
              'slide-center': activeIndex === index,
              'slide-side': activeIndex !== index,
              'initialized': activeIndex >= 0
            }">
            
            <div class="title" :title="plant.name">{{ plant.name }} </div>
            <div class="card-content">
              <img :src="getImage(plant.image)"/>
            <div class="common-content">
              <p>位置:{{ plant.location }}</p>
            </div>
            <div class="full-content">
              <p >类型:{{ plant.type }}</p>
              <p >数量:{{ plant.num }}台</p>
            </div>
            </div>
          </div>
        </swiper-slide>
        <img ref="prevRef" class="left-arrow" src="@/assets/arrow-left.png"/>
        <img ref="nextRef" class="right-arrow" src="@/assets/arrow-right.png" />
      </swiper>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Navigation, Autoplay, EffectFade, Controller } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/effect-fade';

// Swiper 模块
const modules = [Navigation, Autoplay, EffectFade, Controller];

// Swiper 实例引用
const mainSwiperRef = ref<any>(null);
let mainSwiper: any = null;

// 当前激活的幻灯片索引
const activeIndex = ref(0);

// 获取图片资源
const getImage = (name: string) => {
  return new URL(`../assets/${name}.png`, import.meta.url).href
}

interface TestPlant {
  name: string
  location: string
  image?: string
  num?: number
  type?: string
}

// 定义组件属性
interface Props {
  title?: string;
  autoPlayDelay?: number;
  speed?: number;
  hasLoaded?: boolean;
  plants: TestPlant[];
}

const props = withDefaults(defineProps<Props>(), {
  autoPlayDelay: 3000,
  speed: 800,
  hasLoaded: false,
  plants: []
});



// 定义事件
const emit = defineEmits(['swiper-change'])

// 设置主 Swiper 实例
const setMainSwiper = (swiper: any) => {
  mainSwiper = swiper;
};

// 幻灯片切换回调
const onSlideChange = (index) => {
  if (mainSwiper) {
    activeIndex.value = mainSwiper.realIndex;
    emit('swiper-change', slides.value[activeIndex.value]);
  }
};

// 使用传入的幻灯片数据或默认数据
const slides = computed(() => props.plants || []);

// 监听数据加载状态
watch(
  () => props.hasLoaded,
  (newVal) => {
    if (newVal && mainSwiper) {
      mainSwiper.update();
      emit('swiper-change', slides.value[mainSwiper.realIndex]);
    }
  },
  { immediate: true }
);
</script>
<style scoped>
<style>
.seamless-carousel-container {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
}

.carousel-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: visible;
  padding: 0;
}

.swiper {
  height: 170px !important;
}

.swiper .left-arrow {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  display: inline-block;
  margin: auto;
  width: 34px;
  height: 34px;
  z-index: 99;
  cursor: pointer;
}

.swiper .right-arrow {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  display: inline-block;
  margin: auto;
  width: 34px;
  height: 34px;
  z-index: 99;
  cursor: pointer;
}

.main-swiper {
  width: 100%;
  height: 170px;
}

.main-swiper .swiper-slide {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  height: 170px;
}

.main-swiper .swiper-slide.swiper-slide-active .test-plant-card {
  width: 500px !important;
  border: 2px solid #FFA200;
}

/* 卡片样式 */
.test-plant-card {
  overflow: hidden;
  transition: all 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.main-swiper .swiper-slide .test-plant-card {
  width: 190px !important;
  height: 170px;
  background: white;
  border-radius: 8px;
  padding: 22px 20px 20px;
  box-sizing: border-box;
  box-shadow: 0px 0px 10px 0px rgba(6, 0, 1, 0.05);
  flex-shrink: 0;
  transition: all 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.main-swiper .swiper-slide .test-plant-card .title {
  font-size: 20px;
  font-weight: 600;
  color: #666666;
  font-family: "MiSans-semibold";
  margin-bottom: 20px;
  width: 100%;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}

/* 激活状态下的样式 */
.main-swiper .swiper-slide.swiper-slide-active .test-plant-card .title {
  color: #282828;
  margin-bottom: 18px;
}
</style>

使用方法

  1. 引入组件:在需要使用的地方引入组件:
vue 复制代码
<script setup>
import SeamlessCarousel from './SeamlessCarousel.vue';
// 如果需要监听卡片切换事件,请定义此方法
const handleSlideChange = (currentPlant) => {
  console.log('当前选中的卡片:', currentPlant);
};
</script>
  1. 定义数据:定义需要展示的卡片数据,可以是静态数据,也可以是动态数据。
vue 复制代码
<script setup>
const plants = [
    {
        name: 'Plant 1',
        location: 'Location 1',
        image: 'plant1.png',
        num: 10,
        type: 'Type 1'
           
    },
    ... more plants
]
</script>
  1. 配置参数:根据需要配置组件的参数,如自动播放延迟、切换速度、数据加载状态等。
  2. 渲染组件:将组件渲染到页面中。
vue 复制代码
<template>
  
  <SeamlessCarousel 
    :auto-play-delay="5000"
    :speed="1000"
    :has-loaded="true"
    @swiper-change="handleSlideChange"
  />
</template>
  1. 监听卡片切换事件:如果需要监听卡片切换事件,请定义一个方法,并绑定到组件的 swiper-change 事件上。

  2. 运行程序:在浏览器中运行程序,即可看到效果。

注意事项:
  1. 确保已安装所需的依赖包。
  2. 确保已正确配置组件的参数,如自动播放延迟、切换速度、数据加载状态等。
  3. 确保已正确定义数据源,数据源可以是静态数据,也可以是动态数据。
  4. 确保已正确渲染组件,并绑定了监听事件。
  5. 运行程序并查看效果。
相关推荐
民乐团扒谱机2 小时前
【数模美赛=美术大赛?】O奖论文图片复刻——高级绘图matlab代码集锦,让你摆脱画图“一眼MATLAB”的痛苦!
前端·人工智能·matlab
shehuiyuelaiyuehao2 小时前
图书管理系统
java·服务器·前端
打小就很皮...2 小时前
Vditor 实现混合模式评论,使用 Zustand 本地存储
前端·vditor·enablecomment
小二·10 小时前
Python Web 开发进阶实战 :AI 原生数字孪生 —— 在 Flask + Three.js 中构建物理世界实时仿真与优化平台
前端·人工智能·python
Whisper_Sy10 小时前
Flutter for OpenHarmony移动数据使用监管助手App实战 - 网络状态实现
android·java·开发语言·javascript·网络·flutter·php
新缸中之脑11 小时前
Weave.js:开源实时白板库
开发语言·javascript·开源
Amumu1213811 小时前
Vue组件化编程
前端·javascript·vue.js
We་ct11 小时前
LeetCode 6. Z 字形变换:两种解法深度解析与优化
前端·算法·leetcode·typescript
小二·12 小时前
Python Web 开发进阶实战(终章):从单体应用到 AI 原生生态 —— 45 篇技术演进全景与未来开发者生存指南
前端·人工智能·python