Vue實(shí)現(xiàn)輪播圖組件的封裝
輪播圖功能-獲取數(shù)據(jù)
目標(biāo): 基于pinia獲取輪播圖數(shù)據(jù)
核心代碼:
(1)在types/data.d.ts文件中定義輪播圖數(shù)據(jù)的類(lèi)型聲明
// 所有接口的通用類(lèi)型
export type ApiRes <T> = {
code: string,
msg: string,
result: T
}
// 輪播圖類(lèi)型
export type BannerItem = {
hrefUrl: string
id: string
imgUrl: string
type: string
}
(2)在store/home.ts文件中封裝接口,用于獲取輪播圖數(shù)據(jù)
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中導(dǎo)入
import useCategoryStore from './modules/category'
import useHomeStore from './modules/home'
export default function useStore() {
return {
category: useCategoryStore(),
home: useHomeStore(),
}
}
(4)通過(guò)開(kāi)發(fā)者工具查看數(shù)據(jù)
<script lang="ts" setup>
import useStore from '@/store'
const { home } = useStore()
home.getBannerList()
</script>

輪播圖-通用輪播圖組件
項(xiàng)目中會(huì)多次使用到輪播圖組件,但是輪播圖渲染的數(shù)據(jù)是不一樣的。
但是輪播圖的基本功能都是一樣的,比如圖片切換,自動(dòng)播放等等。
因此需要封裝一個(gè)通用的輪播圖組件。
(1)通用輪播圖的基本結(jié)構(gòu)src/components/carousel/index.vue
fade 類(lèi):用于控制圖片的顯示和隱藏
active 類(lèi):用于控制小圓點(diǎn)高亮
<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="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn prev"
><i class="iconfont icon-angle-left"></i
></a>
<a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn next"
><i class="iconfont icon-angle-right"></i
></a>
<div class="carousel-indicator">
<span class="active"></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
</template>
<style scoped lang="less">
.xtxcarousel {
width: 100%;
height: 100%;
min-width: 300px;
min-height: 150px;
position: relative;
.carousel {
&-body {
width: 100%;
height: 100%;
}
&-item {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
opacity: 0;
transition: opacity 0.5s linear;
&.fade {
opacity: 1;
z-index: 1;
}
img {
width: 100%;
height: 100%;
}
}
&-indicator {
position: absolute;
left: 0;
bottom: 20px;
z-index: 2;
width: 100%;
text-align: center;
span {
display: inline-block;
width: 12px;
height: 12px;
background: rgba(0, 0, 0, 0.2);
border-radius: 50%;
cursor: pointer;
~ span {
margin-left: 12px;
}
&.active {
background: #fff;
}
}
}
&-btn {
width: 44px;
height: 44px;
background: rgba(0, 0, 0, 0.2);
color: #fff;
border-radius: 50%;
position: absolute;
top: 228px;
z-index: 2;
text-align: center;
line-height: 44px;
opacity: 0;
transition: all 0.5s;
&.prev {
left: 20px;
}
&.next {
right: 20px;
}
}
}
&:hover {
.carousel-btn {
opacity: 1;
}
}
}
</style>
(2)全局注冊(cè)通用輪播圖 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)覆蓋樣式,控制箭頭和小圓點(diǎn)的位置src/views/home/components/home-banner.vue
:deep(.carousel-btn.prev) {
left: 270px!important;
}
:deep(.carousel-indicator) {
padding-left: 250px;
}
(5)查看效果

輪播圖-數(shù)據(jù)渲染
目的
home-banner組件把數(shù)據(jù)傳遞給Carousel組件進(jìn)行渲染
(1)父?jìng)髯拥姆绞綄?shù)據(jù)傳給通用輪播圖組件src/views/home/components/home-banner.vue
<Carousel :slides="home.bannerList"></Carousel>
(2)子組件接收數(shù)據(jù)src/components/carousel/index.vue
了解寫(xiě)法:如果通過(guò)js的方法定義類(lèi)型,需要單獨(dú)引入PropType進(jìn)行編寫(xiě)
<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)渲染輪播圖數(shù)據(jù)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="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn prev">
<i class="iconfont icon-angle-left"></i>
</a>
<a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn next">
<i class="iconfont icon-angle-right"></i>
</a>
<div class="carousel-indicator">
<span v-for="item in slides" :key="item.id" class="active"></span>
</div>
</div>
</template>
(4)控制高亮的下標(biāo)
<script lang="ts" setup name="Carousel"> const active = ref(0) </script>
(5)高亮渲染
- 添加的fade的圖片才會(huì)展示,所以根據(jù)當(dāng)前索引號(hào)進(jìn)行判斷,索引號(hào)等于active的才進(jìn)行展示
- 添加了active類(lèi)名的小圓點(diǎn)才會(huì)高亮,高亮邏輯跟圖片一致
<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="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn prev">
<i class="iconfont icon-angle-left"></i>
</a>
<a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn next">
<i class="iconfont icon-angle-right"></i>
</a>
<div class="carousel-indicator">
<span
+ v-for="(item, index) in slides"
:key="item.id"
+ :class="{ active: active === index }"
></span>
</div>
</div>
</template>
輪播圖-邏輯封裝
實(shí)現(xiàn)需求:
輪播圖里面的圖片需要從父組件傳入(因?yàn)檩啿ソM件可以復(fù)用)
父組件需要控制輪播圖的是否自動(dòng)播放、動(dòng)畫(huà)時(shí)間(處理默認(rèn)值邏輯)
是否自動(dòng)播放和動(dòng)畫(huà)時(shí)間都是需要默認(rèn)值的(如果不傳就可以使用輪播組件自己提供的默認(rèn)值)
播放邏輯
- 點(diǎn)擊小圓點(diǎn)可以切換圖片
- 點(diǎn)擊prev和next按鈕可以播放指定圖片(根據(jù)圖片個(gè)數(shù)判斷播放的循環(huán))
- 如果父組件配置了自動(dòng)播放,則需要定時(shí)播放圖片
- 鼠標(biāo)進(jìn)入輪播圖,暫停輪播
- 鼠標(biāo)離開(kāi)輪播圖,繼續(xù)輪播
- 注意點(diǎn):組件卸載的時(shí)候需要清除定時(shí)輪播效果(不然組件重新加載的時(shí)候會(huì)導(dǎo)致多個(gè)定時(shí)器開(kāi)啟)
(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 = () => {
// 如果沒(méi)有自動(dòng)播放
if (!props.autoPlay) return
// 在ts中,使用定時(shí)器,window.setInterval
timer = window.setInterval(() => {
next()
}, props.duration)
}
const stop = () => {
clearInterval(timer)
}
let timer = -1
// 自動(dòng)播放
onMounted(() => {
play()
})
onUnmounted(() => {
stop()
})
</script>
(4)鼠標(biāo)進(jìn)入和離開(kāi)操作
<div class="carousel" @mouseenter="stop" @mouseleave="play">
(5)鼠標(biāo)經(jīng)過(guò)小圓點(diǎn)切換
<span
v-for="(item, index) in slides"
:key="item.id"
:class="{ active: active === index }"
@mouseenter="active = index"
></span>
(6)點(diǎn)擊左右箭頭切換
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++
}
}
// 注冊(cè)事件
<a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn prev" @click="prev">
<i class="iconfont icon-angle-left"></i>
</a>
<a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn next" @click="next">
<i class="iconfont icon-angle-right"></i>
</a>
vascript
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++
}
}
// 注冊(cè)事件
<a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn prev" @click="prev">
<i class="iconfont icon-angle-left"></i>
</a>
<a href="javascript:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="carousel-btn next" @click="next">
<i class="iconfont icon-angle-right"></i>
</a>
到此這篇關(guān)于Vue實(shí)現(xiàn)輪播圖組件的封裝的文章就介紹到這了,更多相關(guān)Vue輪播圖組件封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Vue項(xiàng)目中集成和使用Lottie動(dòng)畫(huà)庫(kù)的步驟詳解
Lottie 是一個(gè)由 Airbnb 開(kāi)源的動(dòng)畫(huà)庫(kù),它允許你在 Web、iOS、Android 等平臺(tái)上使用體積小、高性能的體驗(yàn)豐富的矢量動(dòng)畫(huà),本文將詳細(xì)介紹在 Vue 項(xiàng)目中如何集成和使用 Lottie,文中有詳細(xì)的代碼講解,需要的朋友可以參考下2023-11-11
Vue data的數(shù)據(jù)響應(yīng)式到底是如何實(shí)現(xiàn)的
這篇文章主要介紹了Vue data的數(shù)據(jù)響應(yīng)式到底是如何實(shí)現(xiàn)的,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
vue實(shí)現(xiàn)element表格里表頭信息提示功能(推薦)
小編最近接了這樣一個(gè)需求,需要在element表格操作一欄添加提示功能,下面小編給大家?guī)?lái)了基于vue實(shí)現(xiàn)element表格里表頭信息提示功能,需要的朋友參考下吧2019-11-11
vue前端代碼如何通過(guò)maven打成jar包運(yùn)行
這篇文章主要介紹了vue前端代碼如何通過(guò)maven打成jar包運(yùn)行問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
使用Vue如何寫(xiě)一個(gè)雙向數(shù)據(jù)綁定(面試常見(jiàn))
這篇文章主要介紹了使用Vue如何寫(xiě)一個(gè)雙向數(shù)據(jù)綁定,在前端面試過(guò)程中經(jīng)常會(huì)問(wèn)到,文中主要實(shí)現(xiàn)v-model,v-bind 和v-click三個(gè)命令,其他命令也可以自行補(bǔ)充。需要的朋友可以參考下2018-04-04
Vue中l(wèi)ocalStorage的用法和監(jiān)聽(tīng)localStorage值的變化
這篇文章主要介紹了Vue中l(wèi)ocalStorage的用法和監(jiān)聽(tīng)localStorage值的變化,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04

