实现功能
可以根据图片大小控制组件大小
实现左右箭头切图
实现小猫点切图
自动轮播
实现步骤
给组件传递需要的值(图片数组,轮播图的宽高,是否自动播放)
app.vue使用carousel.vue组件
<template>
<div>
<carousel :imagesList="imagesList" :style="imageOption" :autoplay="true"></carousel>
</div>
</template>
<script setup>
import carousel from './components/carousel.vue';
import { ref } from 'vue';
import image1 from './assets/images/1.jpg'
import image2 from './assets/images/2.jpg'
import image3 from './assets/images/3.jpg'
const imagesList = ref([image1, image2, image3])
const imageOption = ref({
width: '1240px',
height: '500px'
})
</script>
<style scoped lang="less"></style>
编写carousel.vue组件
控制传入的参数,css调整
使用ul>li遍历展示图片,将图片使用定位,把所有图片重合在一起,且设置图片为透明
通过currIndex属性控制当前索引的图片透明度为1(展示)
<template>
<div class="carousel">
<!-- 轮播的图片 -->
<ul class="carousel-list">
<li class="imageList" v-for="item, index in imagesList" :key="index" :class="{ fade: index === currIndex }">
<a href="javascript:;">
<img :src="item" alt="">
</a>
</li>
</ul>
</div>
</template>
<script setup>
import { defineProps, ref,watch } from 'vue';
const props = defineProps({
imagesList: {
type: Array,
dedfault: () => ([])
},
style: {
type: Object,
default: {
width: '1000px',
height: '500px'
}
},
autoplay:{
type:Boolean,
default:true
}
})
// 当前图片索引
const currIndex = ref(0)
</script>
<style scoped lang="less">
a {
display: inline-block;
}
img {
width: 100%;
height: 100%;
}
.carousel {
// width: 100%;
// height: 100%;
position: relative;
.carousel-list {
list-style: none;
.imageList {
// 图片定位,重叠
position: absolute;
left: 0;
top: 0;
opacity: 0;
// 过度动画
transition: opacity 0.5 linear;
&.fade {
opacity: 1;
z-index: 1;
}
}
}
}</style>
编写左右箭头控制图片切换及js逻辑实现
<!-- 左右箭头 -->
<div class="right" @click="change(1)">
<i class="iconfont icon-right"></i>
</div>
<div class="left" @click="change(-1)">
<i class="iconfont icon-left"></i>
</div>
在跟标签下加入左右箭头,用来控制图片切换
// 切换图片
const change = (step) => {
if (step > 0) {
currIndex.value += 1
if (currIndex.value > props.imagesList.length - 1) {
currIndex.value = 0
}
} else {
currIndex.value -= 1
if (currIndex.value < 0) {
currIndex.value = props.imagesList.length - 1
}
}
}
通过change函数的参数step控制图片左右切换,判断索引是否超出图片索引,若超出索引则索引归位
下方指示器切换图片
<!-- 下方的标点 -->
<div class="biaodian">
<span v-for="item, index in imagesList" @click="changeIndex(index)" :key="index" :class="{active:index===currIndex}"></span>
</div>
在跟标签加入指示器用来切换标签,通过图片数组的长度来判断指示器的点数,点击指示器获得该指示器的索引,同时切换currindex的值,达到切换图片的效果
// 点击标点切换
const changeIndex=(index)=>{
currIndex.value=index
}
自动轮播
// 自动播放
let timer=null
const autoplayFn=()=>{
clearInterval(timer)
timer=setInterval(()=>{
change(1)
// currIndex.value++
// if(currIndex.value>=props.imagesList.length){
// currIndex.value=0
// }
},2000)
}
// 监听定时器
watch(()=>props.imagesList,(newVal)=>{
// 有图片 且 自动播放为true
if(newVal.length&&props.autoplay){
autoplayFn()
}
},{immediate:true})
// 鼠标进入,停止自动轮播
const stop=()=>{
if(timer)
clearInterval(timer)
}
使用监听watch实现
设置一个定时器,每两秒执行change(1)函数,使得图片的currIndex+1,来切换图片
立即监听图片数组,若图片数组发生变化(页面挂载完毕,图片数组从无到有),就判断是否有图片且参数是否为自动切换,若是则执行autoplayFn函数,开始自动轮播
鼠标进入轮播图停止自动轮播,离开继续自动轮播
<div class="carousel" @mouseenter="stop()" @mouseleave="start()" :style="{ width: props.style.width, height: props.style.height }">
内容
</div>
在跟标签加上鼠标进入,离开事件,执行对应的函数
// 鼠标进入,停止自动轮播
const stop=()=>{
if(timer)
clearInterval(timer)
}
// 鼠标离开,开始轮播
const start=()=>{
if(props.autoplay)
autoplayFn()
}
页面卸载去掉定时器
onUnmounted(()=>{
clearInterval(timer)
})
完整代码(carousel.vue)
<template>
<div class="carousel" @mouseenter="stop()" @mouseleave="start()" :style="{ width: props.style.width, height: props.style.height }">
<!-- 轮播的图片 -->
<ul class="carousel-list">
<li class="imageList" v-for="item, index in imagesList" :key="index" :class="{ fade: index === currIndex }">
<a href="javascript:;">
<img :src="item" alt="">
</a>
</li>
</ul>
<!-- 下方的标点 -->
<div class="biaodian">
<span v-for="item, index in imagesList" @click="changeIndex(index)" :key="index" :class="{active:index===currIndex}"></span>
</div>
<!-- 左右箭头 -->
<div class="right" @click="change(1)">
<i class="iconfont icon-right"></i>
</div>
<div class="left" @click="change(-1)">
<i class="iconfont icon-left"></i>
</div>
</div>
</template>
<script setup>
import { defineProps, ref,watch,onUnmounted } from 'vue';
const props = defineProps({
imagesList: {
type: Array,
dedfault: () => ([])
},
style: {
type: Object,
default: {
width: '1000px',
height: '500px'
}
},
autoplay:{
type:Boolean,
default:true
}
})
// 当前图片索引
const currIndex = ref(0)
// 切换图片
const change = (step) => {
if (step > 0) {
currIndex.value += 1
if (currIndex.value > props.imagesList.length - 1) {
currIndex.value = 0
}
} else {
currIndex.value -= 1
if (currIndex.value < 0) {
currIndex.value = props.imagesList.length - 1
}
}
}
// 点击标点切换
const changeIndex=(index)=>{
currIndex.value=index
}
// 自动播放
let timer=null
const autoplayFn=()=>{
clearInterval(timer)
timer=setInterval(()=>{
change(1)
// currIndex.value++
// if(currIndex.value>=props.imagesList.length){
// currIndex.value=0
// }
},2000)
}
// 监听定时器
watch(()=>props.imagesList,(newVal)=>{
// 有图片 且 自动播放为true
if(newVal.length&&props.autoplay){
autoplayFn()
}
},{immediate:true})
// 鼠标进入,停止自动轮播
const stop=()=>{
if(timer)
clearInterval(timer)
}
// 鼠标离开,开始轮播
const start=()=>{
if(props.autoplay)
autoplayFn()
}
onUnmounted(()=>{
clearInterval(timer)
})
</script>
<style scoped lang="less">
a {
display: inline-block;
}
img {
width: 100%;
height: 100%;
}
.carousel {
// width: 100%;
// height: 100%;
position: relative;
.carousel-list {
list-style: none;
.imageList {
// 图片定位,重叠
position: absolute;
left: 0;
top: 0;
opacity: 0;
// 过度动画
transition: opacity 0.5 linear;
&.fade {
opacity: 1;
z-index: 1;
}
}
}
.right,
.left {
position: absolute;
width: 30px;
height: 30px;
i {
font-size: 30px;
}
}
.right {
top: 50%;
right: 0;
z-index: 999;
}
.left {
top: 50%;
left: 0;
z-index: 999;
}
.biaodian {
position: absolute;
bottom: 5px;
left: 50%;
width: 200px;
height: 20px;
z-index: 999;
span {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #999;
~span{
margin-left: 20px;
}
&.active{
background-color: red;
}
}
}
}</style>