这篇文章主要介绍“Vue怎么实现轮播图组件封装”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue怎么实现轮播图组件封装”文章能帮助大家解决问题。
轮播图功能-获取数据
目标: 基于pinia获取轮播图数据
核心代码:
(1)在
types/data.d.ts文件中定义轮播图数据的类型声明
// 所有接口的通用类型
export type ApiRes <T> = {
    code: string,
    msg: string,
    result: T
}
// 轮播图类型
export type BannerItem = {
  hrefUrl: string
  id: string
  imgUrl: string
  type: string
}(2)在
store/home.ts文件中封装接口,用于获取轮播图数据
import { ApiRes, BannerItem } from '@/types/data'
import request from '@/utils/request'
import { defineStore } from 'pinia'
export default defineStore('home', {
  state: () => ({
    bannerList: [] as BannerItem[],
  }),
  actions: {
    async getBannerList() {
      const {data: res} = await request.get<ApiRes<BannerItem[]>>('/home/banner')
      this.bannerList = res.result
    },
  },
})(3)在
store/index.ts中导入
import useCategoryStore from './modules/category'
import useHomeStore from './modules/home'
export default function useStore() {
  return {
    category: useCategoryStore(),
    home: useHomeStore(),
  }
}(4)通过开发者工具查看数据
<script lang="ts" setup>
import useStore from '@/store'
const { home } = useStore()
home.getBannerList()
</script>轮播图-通用轮播图组件
项目中会多次使用到轮播图组件,但是轮播图渲染的数据是不一样的。
但是轮播图的基本功能都是一样的,比如图片切换,自动播放等等。
因此需要封装一个通用的轮播图组件。
(1)通用轮播图的基本结构
src/components/carousel/index.vue
fade 类:用于控制图片的显示和隐藏
active 类:用于控制小圆点高亮
<script lang="ts" setup name="Carousel"> defineProps() </script> <template> <div class="carousel"> <ul class="carousel-body"> <li class="carousel-item fade"> <RouterLink to="/"> <img src="http://yjy-xiaotuxian-dev.oss-cn-beijing.aliyuncs.com/picture/2021-04-15/1ba86bcc-ae71-42a3-bc3e-37b662f7f07e.jpg" alt="" /> </RouterLink> </li> <li class="carousel-item"> <RouterLink to="/"> <img src="http://yjy-xiaotuxian-dev.oss-cn-beijing.aliyuncs.com/picture/2021-04-15/1ba86bcc-ae71-42a3-bc3e-37b662f7f07e.jpg" alt="" /> </RouterLink> </li> <li class="carousel-item"> <RouterLink to="/"> <img src="http://yjy-xiaotuxian-dev.oss-cn-beijing.aliyuncs.com/picture/2021-04-15/1ba86bcc-ae71-42a3-bc3e-37b662f7f07e.jpg" alt="" /> </RouterLink> </li> </ul> <a href="https://www.maopiaopiao.com">
(2)全局注册通用轮播图
src/components/index.ts
import type { App } from 'vue'
import skelecton from './skeleton/index.vue'
+import Carousel from './carousel/index.vue'
export default {
  install(app: App) {
    app.component(skelecton.name, skelecton)
+    app.component(Carousel.name, Carousel)
  },
}(3)在广告组件中使用
src/views/home/components/home-banner.vue
<template> <div class="home-banner"> <!-- 轮播图 --> <Carousel></XtxCarousel> </div> </template>
(4)覆盖样式,控制箭头和小圆点的位置
src/views/home/components/home-banner.vue
:deep(.carousel-btn.prev) {
  left: 270px!important;
}
:deep(.carousel-indicator) {
  padding-left: 250px;
}轮播图-数据渲染
目的
home-banner组件把数据传递给Carousel组件进行渲染
(1)父传子的方式将数据传给通用轮播图组件
src/views/home/components/home-banner.vue
<Carousel :slides="home.bannerList"></Carousel>
(2)子组件接收数据
src/components/carousel/index.vue
了解写法:如果通过js的方法定义类型,需要单独引入PropType进行编写
<script lang="ts" setup name="Carousel">
import { BannerItem } from '@/types/data'
// import { PropType } from 'vue'
// defineProps({
//   slides: {
//     type: Array as PropType<BannerItem[]>,
//     required: true,
//   },
// })
defineProps<{
  slides: BannerItem[]
}>()
</script>(3)渲染轮播图数据
src/components/carousel/index.vue
<template> <div class="carousel"> <ul class="carousel-body"> <li class="carousel-item fade" v-for="item in slides" :key="item.id"> <RouterLink :to="item.hrefUrl"> <img :src="item.imgUrl" alt="" /> </RouterLink> </li> </ul> <a href="https://www.maopiaopiao.com">
(4)控制高亮的下标
<script lang="ts" setup name="Carousel"> const active = ref(0) </script>
(5)高亮渲染
添加的fade的图片才会展示,所以根据当前索引号进行判断,索引号等于active的才进行展示
添加了active类名的小圆点才会高亮,高亮逻辑跟图片一致
<template>
  <div class="carousel">
    <ul class="carousel-body">
      <li
        class="carousel-item"
+        :class="{ fade: active === index }"
+        v-for="(item, index) in slides"
        :key="item.id"
      >
        <RouterLink :to="item.hrefUrl">
          <img :src="item.imgUrl" alt="" />
        </RouterLink>
      </li>
    </ul>
    <a href="https://www.maopiaopiao.com">轮播图-逻辑封装
实现需求:
轮播图里面的图片需要从父组件传入(因为轮播组件可以复用)
父组件需要控制轮播图的是否自动播放、动画时间(处理默认值逻辑)
是否自动播放和动画时间都是需要默认值的(如果不传就可以使用轮播组件自己提供的默认值)
播放逻辑
点击小圆点可以切换图片
点击prev和next按钮可以播放指定图片(根据图片个数判断播放的循环)
如果父组件配置了自动播放,则需要定时播放图片
鼠标进入轮播图,暂停轮播
鼠标离开轮播图,继续轮播
注意点:组件卸载的时候需要清除定时轮播效果(不然组件重新加载的时候会导致多个定时器开启)
(1)父组件传值给轮播图
src/views/home/components/home-banner.vue
<template> <div class="home-banner"> <!-- 轮播图 --> <Carousel :slides="slides" autoPlay :duration="3000"></XtxCarousel> </div> </template>
(2)props接收
src/components/Carousel.vue
<script lang="ts" setup name="Carousel">
import { BannerItem } from '@/types/data'
import { ref, PropType } from 'vue'
defineProps({
  slides: {
    type: Array as PropType<BannerItem[]>,
    required: true,
  },
  autoPlay: {
    type: Boolean,
    default: false,
  },
  duration: {
    type: Number,
    default: 3000,
  },
})
const active = ref(0)
</script>(3)轮播图的播放逻辑
<script lang="ts" setup name="Carousel">
import { BannerItem } from '@/types/data'
import { onMounted, onUnmounted, PropType, ref } from 'vue'
// import { PropType } from 'vue'
const props = defineProps({
  slides: {
    type: Array as PropType<BannerItem[]>,
    required: true,
  },
  duration: {
    type: Number,
    default: 3000,
  },
  autoPlay: {
    type: Boolean,
    default: false,
  },
})
// const props = defineProps<{
//   slides: BannerItem[]
// }>()
// 控制高亮
const active = ref(0)
const prev = () => {
  if (active.value <= 0) {
    active.value = props.slides.length - 1
  } else {
    active.value--
  }
}
const next = () => {
  if (active.value >= props.slides.length - 1) {
    active.value = 0
  } else {
    active.value++
  }
}
const play = () => {
  // 如果没有自动播放
  if (!props.autoPlay) return
  // 在ts中,使用定时器,window.setInterval
  timer = window.setInterval(() => {
    next()
  }, props.duration)
}
const stop = () => {
  clearInterval(timer)
}
let timer = -1
// 自动播放
onMounted(() => {
  play()
})
onUnmounted(() => {
  stop()
})
</script>(4)鼠标进入和离开操作
<div class="carousel" @mouseenter="stop" @mouseleave="play">
(5)鼠标经过小圆点切换
<span
  v-for="(item, index) in slides"
  :key="item.id"
  :class="{ active: active === index }"
  @mouseenter="active = index"
></span>(6)点击左右箭头切换
const prev = () => {
  if (active.value === 0) {
    active.value = props.slides.length - 1
  } else {
    active.value--
  }
}
const next = () => {
  if (active.value === props.slides.length - 1) {
    active.value = 0
  } else {
    active.value++
  }
}
// 注册事件
<a href="https://www.maopiaopiao.com">