手写轮播图组件

实现功能

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

实现左右箭头切图

实现小猫点切图

自动轮播

实现步骤

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

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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的组件的实现: ```html <template> <div class="carousel"> <!-- 可视区域 --> <div class="viewport"> <div class="slider" :style="{ transform: `translateX(${translateX}px)` }"> <div class="slide" v-for="(item, index) in items" :key="index"> <img :src="item.imgUrl" alt=""> </div> </div> </div> <!-- 控制按钮 --> <div class="buttons"> <button class="prev" @click="prev"><</button> <button class="next" @click="next">></button> </div> <!-- 指示器 --> <div class="indicators"> <span class="indicator" v-for="(item, index) in items" :key="index" :class="{ active: index === currentIndex }" @click="jumpTo(index)"></span> </div> </div> </template> <script> export default { name: 'Carousel', props: { items: { type: Array, default: () => [] } }, data() { return { currentIndex: 0, // 当前显示的片索引 translateX: 0 // slider 的 translateX 值 } }, methods: { // 切换到上一张片 prev() { if (this.currentIndex > 0) { this.currentIndex--; this.translateX += this.slideWidth; } else { this.currentIndex = this.items.length - 1; this.translateX = -this.slideWidth * (this.items.length - 1); } }, // 切换到下一张片 next() { if (this.currentIndex < this.items.length - 1) { this.currentIndex++; this.translateX -= this.slideWidth; } else { this.currentIndex = 0; this.translateX = 0; } }, // 跳转到指定片 jumpTo(index) { this.currentIndex = index; this.translateX = -this.slideWidth * index; } }, computed: { slideWidth() { return this.$refs.slider.offsetWidth; } } } </script> <style scoped> .carousel { position: relative; width: 100%; overflow: hidden; } .viewport { position: relative; overflow: hidden; } .slider { display: flex; transition: transform 0.3s ease-out; } .slide { flex-shrink: 0; width: 100%; text-align: center; } .buttons { position: absolute; top: 50%; transform: translateY(-50%); z-index: 1; } .buttons button { font-size: 2rem; color: #fff; background-color: rgba(0, 0, 0, 0.5); border: none; outline: none; cursor: pointer; padding: 0.5rem; margin: 0 1rem; } .indicators { position: absolute; bottom: 1rem; left: 50%; transform: translateX(-50%); z-index: 1; display: flex; } .indicator { width: 1rem; height: 1rem; border-radius: 50%; background-color: #fff; margin: 0 0.5rem; cursor: pointer; } .indicator.active { background-color: #f00; } </style> ``` 这个组件的主要思路是利用 flex 布局和 translateX 属性实现片的滑动。其中,控制按钮和指示器使用了绝对定位的方式进行布局。具体实现过程中,我们需要获取 slider 的宽度,以便计算出 translateX 的值。同时,我们还需要在切换到第一张或最后一张片时,调整 translateX 的值,以实现循环滑动的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值