《VUE》走马灯组件
<template> <!-- 走马灯 --> <div class="box"> <div class="carousel"> <div class="item" v-for="(v,i) in list" :key="i" @click="open(v)"> <img :src="v.img" alt=""> <!-- 走马灯图中自定义内容 --> <slot :current="current"></slot> </div> </div> <div class="indicator" v-if="isIndicator"> <span :class="{'active': current == i}" v-for="(v,i) in list" :key="i" @click="indicatorCheck(i)"></span> </div> <template v-if="isArrow"> <div class="arrow_left" @click="arrowNext(1)"></div> <div class="arrow_right" @click="arrowNext(2)"></div> </template> </div> </template>
<script> export default { props: { // 走马灯列表 list: { type: Array, required: true, default: () => [] // { img: require(''), link: '' } }, // 是否显示下方指示点 isIndicator: { type: Boolean, default: false }, // 是否显示左右箭头 isArrow: { type: Boolean, default: false }, // 自动切换的时间间隔,单位为毫秒 interval: { type: Number, default: 3000 } }, data() { return { current: 0, // 当前在第几张图 indicator: 1, timer: null, } }, mounted() { this.init() this.autoRun() }, destroyed() { clearInterval(this.timer) }, methods: { // 初始化走马灯列表 init() { let carouselDom = document.querySelector('.carousel') // 复制第一张图 let first = carouselDom.firstElementChild.cloneNode(true) // 复制最后一张图 let last = carouselDom.lastElementChild.cloneNode(true) // 将第一张图放在末尾 carouselDom.appendChild(first) // 将最后一张图放在第一张 carouselDom.insertBefore(last, carouselDom.firstElementChild) // 设置最后一张复制图为绝对定位 last.style.position = "absolute" last.style.transform = "translateX(-100%)" }, // 走马灯自动运行 autoRun() { const _this = this if(_this.indicator >= _this.list.length) { _this.indicator = 0 } this.timer = setInterval(() => { this.arrowNext(2) _this.indicator++ if(_this.indicator >= _this.list.length) { _this.indicator = 0 } }, this.interval) }, // 下方指示器事件 indicatorCheck(index) { let carouselDom = document.querySelector('.carousel') let count = this.list.length // 当前在最后一张图时,无缝切换到第一页 if(this.current === count-1 && index === 0) { carouselDom.style.transform = "translateX(100%)" carouselDom.style.transition = 'none' carouselDom.clientHeight // 强制渲染 this.moveTo(0, 'move') } else { this.moveTo(index, 'move') } }, // 走马灯左右箭头事件 arrowNext(type) { let carouselDom = document.querySelector('.carousel') let count = this.list.length // 左箭头 if(type==1) { // 当前是否在第一张图,无缝切换 if(this.current === 0) { carouselDom.style.transform = `translateX(-${count}00%)` carouselDom.style.transition = 'none' carouselDom.clientHeight // 强制渲染 this.moveTo(count-1, 'move') } else { this.moveTo(this.current-1, 'move') } } // 右箭头 if(type==2) { // 当前是否在最后一张图,无缝切换 if(this.current === count-1) { carouselDom.style.transform = "translateX(100%)" carouselDom.style.transition = 'none' carouselDom.clientHeight // 强制渲染 this.moveTo(0, 'move') } else { this.moveTo(this.current+1, 'move') } } }, moveTo(index, type) { if(type=='move') { clearInterval(this.timer) this.indicator = index+1 this.autoRun() } this.current = index let carouselDom = document.querySelector('.carousel') carouselDom.style.transform = `translateX(-${index}00%)` carouselDom.style.transition = '.5s' }, // 跳转 open(v) { if(v.link) { window.open(v.link) } } } } </script>
<style scoped lang="scss"> .box{ width: 100%; height: 700px; margin: 0 auto; overflow: hidden; position: relative; .carousel{ width: 100%; display: flex; transform: translateX(-0%); .item{ width: 100%; position: relative; > img{ width: calc(100vw - 4px); // height: 700px; display: block; } } } .indicator{ position: absolute; bottom: 200px; left: 50%; transform: translateX(-50%); display: flex; justify-content: center; span{ display: block; width: 20px; height: 20px; border: 1px solid #ddd; border-radius: 50%; margin: 0 4px; cursor: pointer; &.active{ background-color: #fff; border-color: #fff; } } } .arrow_left, .arrow_right{ width: 30px; height: 30px; background-color: #ccc; position: absolute; top: 50%; transform: translateY(-50%); cursor: pointer; } .arrow_left{ left: 300px; } .arrow_right{ right: 300px; } } </style>