二级标题
轮播图-通用轮播图组件
项目中会多次使用到轮播图组件,且轮播图渲染的数据是不一样的。轮播图的基本功能都是一样的,比如图片切换,自动播放等等。因此需要封装一个通用的轮播图组件。
轮播图的基本结构
<script lang="ts" setup name="XtxCarousel"> defineProps() </script> <template> <div class="xtx-carousel"> <ul class="carousel-body"> <li class="carousel-item fade"> <RouterLink to="/"> <img src="https://www.qianduange.cn/upload/article/1ba86bcc-ae71-42a3-bc3e-37b662f7f07e.jpg" alt="" /> </RouterLink> </li> <li class="carousel-item"> <RouterLink to="/"> <img src="https://www.qianduange.cn/upload/article/1ba86bcc-ae71-42a3-bc3e-37b662f7f07e.jpg" alt="" /> </RouterLink> </li> <li class="carousel-item"> <RouterLink to="/"> <img src="https://www.qianduange.cn/upload/article/1ba86bcc-ae71-42a3-bc3e-37b662f7f07e.jpg" alt="" /> </RouterLink> </li> </ul> <a href="javascript:;" class="carousel-btn prev" ><i class="iconfont icon-angle-left"></i ></a> <a href="javascript:;" 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"> .xtx-carousel { 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>
复制
逻辑封装
完成轮播图的交互逻辑
● 自动播放,暴露自动轮播属性,设置了就自动轮播
○ 如果有自动播放,鼠标进入离开,暂停,开启
● 指示器切换,上一张,下一张
● 销毁组件,清理定时器
具体代码
<script lang="ts" setup name="XtxCarousel"> import { onBeforeUnmount, onMounted, ref } from "vue"; // duration: 决定切换一张图需要的时间。它就是自动播放的间隔 autoPlay:是否自动播放 const {duration,autoPlay} = defineProps<{duration:number,autoPlay:boolean}>(); const arr = [ "https://gimg2.baidu.com/image_search/src=http://cdn.micuer.com/image_temp/1c6cd32394529b50aa9e847855221828_1200_1200.png&refer=http://cdn.micuer.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1661180945&t=9426000bbc2d3eec4b1207a8b1777220", "https://gimg2.baidu.com/image_search/src=http://i0.hdslb.com/bfs/article/8d802d12bc084b60a805e76d241170095a479408.jpg&refer=http://i0.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1661180945&t=d72a8ba8e8a78f5d442a7efa821fb2a3", "https://gimg2.baidu.com/image_search/src=http://pic1.win4000.com/wallpaper/2019-12-23/5e008399e32fa.jpg&refer=http://pic1.win4000.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1661180945&t=51e0ac7642ecfbe6548aed2a6579aced ", "https://img2.baidu.com/it/u=1912999255,2672254654&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800", "https://img2.baidu.com/it/u=1884557076,4135193950&fm=253&fmt=auto&app=138&f=JPEG?w=909&h=500" ]; // 初始值 默认那个图片选中 let active = ref(0); // 左边按钮 const left = () => { active.value--; // 如果初始值 大于 0 便让初始值 等于 数组的长度减一 if(active.value < 0) { active.value = arr.length-1 } }; // 右边按钮 const right = () => { active.value++; // 如果初始值等于数组的长度变回跳 到 0 if(active.value===arr.length){ active.value=0 } }; // 销毁组件,清理定时器 onBeforeUnmount(()=>{ stop() }) // 自动播放 如果开启了自动播放 则每隔duration 去播放下一张 left() onMounted(()=>{ start() }) let timer = -1 // 开始 // 鼠标离开要继续播放 const start =()=>{ // 如果是true 就开启定时器 if(autoPlay){ timer=window.setInterval(()=>{ right() },duration) } } // 停止 // 鼠标经过要暂停播放 const stop = ()=>{ // 清除定时器 clearInterval(timer) } </script> <template> <div class="xtx-carousel"> <ul class="carousel-body" @mouseleave="start()" @mouseenter="stop()"> <!-- fade 表示当前可见的图片 --> <li class="carousel-item" :class="{ fade: active === index }" v-for="(item, index) in arr" :key="index"> <RouterLink to="/"> <img :src="item" alt="" /> </RouterLink> </li> </ul> <a href="javascript:;" @click="left" class="carousel-btn prev"><i class="iconfont icon-angle-left"></i></a> <a href="javascript:;" @click="right" class="carousel-btn next"><i class="iconfont icon-angle-right"></i></a> <div class="carousel-indicator"> <span @mouseover="active=index" :class="{active:active===index}" v-for="(item,index) in arr" :key="index"></span> <!-- mouseover是鼠标经过 小圆点 高亮 切换图 --> </div> </div> </template> <style scoped lang="less"> .xtx-carousel { 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>
复制
不要忘记全局注册
我这边是在 components 文件下面从新创建一个 index.ts 专门来放 全局注册
// 全局组件注册 import {App} from 'vue' import XtxCarousel from './XtxCarousel/XtxCarousel.vue' export default{ install(app:App){ app.component('XtxCarousel',XtxCarousel) } }
复制
在 在mian.ts 里面导入挂载
import { createApp } from 'vue' import App from './App.vue' // 导入路由 import routers from './ router/index' // 全局组件 import XtxUI from './components/index' const app = createApp(App) app.use(routers) app.use(XtxUI) app.mount('#app')
复制