Vue實現(xiàn)輪播圖組件的封裝
輪播圖功能-獲取數(shù)據(jù)
目標(biāo): 基于pinia獲取輪播圖數(shù)據(jù)
核心代碼:
(1)在types/data.d.ts
文件中定義輪播圖數(shù)據(jù)的類型聲明
// 所有接口的通用類型 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
文件中封裝接口,用于獲取輪播圖數(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)通過開發(fā)者工具查看數(shù)據(jù)
<script lang="ts" setup> import useStore from '@/store' const { home } = useStore() home.getBannerList() </script>
輪播圖-通用輪播圖組件
項目中會多次使用到輪播圖組件,但是輪播圖渲染的數(shù)據(jù)是不一樣的。
但是輪播圖的基本功能都是一樣的,比如圖片切換,自動播放等等。
因此需要封裝一個通用的輪播圖組件。
(1)通用輪播圖的基本結(jié)構(gòu)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="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)全局注冊通用輪播圖 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; }
(5)查看效果
輪播圖-數(shù)據(jù)渲染
目的
home-banner組件把數(shù)據(jù)傳遞給Carousel組件進(jìn)行渲染
(1)父傳子的方式將數(shù)據(jù)傳給通用輪播圖組件src/views/home/components/home-banner.vue
<Carousel :slides="home.bannerList"></Carousel>
(2)子組件接收數(shù)據(jù)src/components/carousel/index.vue
了解寫法:如果通過js的方法定義類型,需要單獨引入PropType進(jìn)行編寫
<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的圖片才會展示,所以根據(jù)當(dāng)前索引號進(jìn)行判斷,索引號等于active的才進(jìn)行展示
- 添加了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="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>
輪播圖-邏輯封裝
實現(xiàn)需求:
輪播圖里面的圖片需要從父組件傳入(因為輪播組件可以復(fù)用)
父組件需要控制輪播圖的是否自動播放、動畫時間(處理默認(rèn)值邏輯)
是否自動播放和動畫時間都是需要默認(rèn)值的(如果不傳就可以使用輪播組件自己提供的默認(rèn)值)
播放邏輯
- 點擊小圓點可以切換圖片
- 點擊prev和next按鈕可以播放指定圖片(根據(jù)圖片個數(shù)判斷播放的循環(huán))
- 如果父組件配置了自動播放,則需要定時播放圖片
- 鼠標(biāo)進(jìn)入輪播圖,暫停輪播
- 鼠標(biāo)離開輪播圖,繼續(xù)輪播
- 注意點:組件卸載的時候需要清除定時輪播效果(不然組件重新加載的時候會導(dǎo)致多個定時器開啟)
(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)鼠標(biāo)進(jìn)入和離開操作
<div class="carousel" @mouseenter="stop" @mouseleave="play">
(5)鼠標(biāo)經(jīng)過小圓點切換
<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="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++ } } // 注冊事件 <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實現(xiàn)輪播圖組件的封裝的文章就介紹到這了,更多相關(guān)Vue輪播圖組件封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue data的數(shù)據(jù)響應(yīng)式到底是如何實現(xiàn)的
這篇文章主要介紹了Vue data的數(shù)據(jù)響應(yīng)式到底是如何實現(xiàn)的,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02vue實現(xiàn)element表格里表頭信息提示功能(推薦)
小編最近接了這樣一個需求,需要在element表格操作一欄添加提示功能,下面小編給大家?guī)砹嘶趘ue實現(xiàn)element表格里表頭信息提示功能,需要的朋友參考下吧2019-11-11使用Vue如何寫一個雙向數(shù)據(jù)綁定(面試常見)
這篇文章主要介紹了使用Vue如何寫一個雙向數(shù)據(jù)綁定,在前端面試過程中經(jīng)常會問到,文中主要實現(xiàn)v-model,v-bind 和v-click三個命令,其他命令也可以自行補(bǔ)充。需要的朋友可以參考下2018-04-04Vue中l(wèi)ocalStorage的用法和監(jiān)聽localStorage值的變化
這篇文章主要介紹了Vue中l(wèi)ocalStorage的用法和監(jiān)聽localStorage值的變化,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04