手写轮播图组件

实现功能

可以根据图片大小控制组件大小

实现左右箭头切图

实现小猫点切图

自动轮播

实现步骤

给组件传递需要的值(图片数组,轮播图的宽高,是否自动播放)

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>

猜你喜欢

转载自blog.csdn.net/m0_57108418/article/details/129769683