readme
```javascript
//走马灯组件 轮播图:
index1.vue: (隐入隐出形式)
/* 实现思路: :class="{ fade: index === i }" 对当前显示
图片动态绑定一个fade属性:
.fade {
opacity: 1;
z-index: 1;
}
实现隐入隐出 */
index2.vue: (无缝衔接形式)
/* 实现思路:
<ul :style="{width: width*(lang+1) +'px',left:`-${leftVal}px`,transition:`${ition}s`}" >
<li v-for="(item, i) in list" :key="i" :style="{ width: width + 'px' }">
<img :src="item.imgUrl" alt="" />
</li>
<!-- 复制第一张放到最后,以实现无缝无线循环滚动效果 -->
<li class="carousel-item" :style="{width: width +'px'}">
<img :src="list[0].imgUrl" alt="">
</li>
</ul>
1、首先复制列表第一个放到最后,以实现无缝滚动的效果:
2、leftVal是左侧位置,ition是动画时间 通过不同的这两个值 实现不同时间的滚动 */
二者使用方法完全相同:
1、引入:
import Carousel from '@/components/Carousel/index.vue'
2、使用:
<Carousel :height="300" :width="500" :list="list" :autoplay="true" :duration="5"></Carousel>
参数说明:{
width: Number, //宽度
height: Number, //高度
list: Array, //图片列表
autoplay:Boolean, //是否自动播放
duration:Number //自动播放时间 单位(s)
}
index1.vue
<script setup>
import { ref, computed, watch,onUnmounted } from "vue";
import {throttle} from '@/utils/DebounceAndthrottle.js'
const props = defineProps({
width: Number,
height: Number,
list: Array,
autoplay:Boolean,
duration:Number
});
//当前图片索引:
const index = ref(0);
//左边按钮
const prev = throttle(() => {
index.value--;
if (index.value < 0) {
index.value = lang.value - 1;
}
},1000);
//右边按钮:
const next = throttle(() => {
index.value++;
if (index.value > lang.value - 1) {
index.value = 0;
}
},1000);
// 计算图片列表的长度
const lang = computed(() => {
return props.list.length;
});
//点击指示器:
const clickindex = (i) => {
index.value = i;
};
// 封装一个自动轮播的函数
const timer = ref(null);
const autoplayFn = () => {
// 防止触发多个定时任务
clearInterval(timer.value);
timer.value = setInterval(() => {
index.value += 1;
if (index.value > lang.value - 1) {
// 超过右侧范围,从头开始
index.value = 0;
}
}, props.duration * 1000);
};
// 侦听器也可以侦听props的数据
//导入鼠标位置控制插件
import { useMouseInElement } from '@vueuse/core'
const target = ref(null)
//isOutside 鼠标是否在目标target外面:
const { isOutside } = useMouseInElement(target)
watch( isOutside,() => {
//如果鼠标移入到盒子里面 ,关闭自动轮播
//鼠标 不在盒子内 可以开启自动轮播
// 轮播图长度大于1并且标志位是放开的
if (lang.value > 1 && props.autoplay && isOutside.value) {
autoplayFn();
}else{
clearInterval(timer.value);
}
},
{ immediate: true }
);
// 组件销毁,清理定时器
onUnmounted(() => {
clearInterval(timer)
})
</script>
<template>
<div
class="xtx-carousel"
:style="{ height: height + 'px', width: width + 'px' }"
ref="target"
>
<ul class="carousel-body">
<!-- 图片 -->
<li
class="carousel-item"
v-for="(item, i) in list"
:key="i"
:class="{ fade: index === i }"
>
<!-- <RouterLink to="/"> -->
<img :src="item.imgUrl" alt="" />
<!-- </RouterLink> -->
</li>
</ul>
<!-- 左右箭头 -->
<a href="javascript:;" class="carousel-btn prev" @click="prev"
><el-icon><ArrowLeftBold /></el-icon
></a>
<a href="javascript:;" class="carousel-btn next" @click="next"
><el-icon><ArrowRightBold /></el-icon
></a>
<!-- 指示小圆点 -->
<div class="carousel-indicator">
<span
v-for="(item, i) in list"
:key="i"
:class="{ active: index === i }"
@click="clickindex(i)"
></span>
</div>
</div>
</template>
<style scoped lang="scss">
.xtx-carousel {
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: 45%;
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>
index2.vue
<script setup>
import { ref, computed, watch,onUnmounted } from "vue";
const props = defineProps({
width: Number,
height: Number,
list: Array,
autoplay:Boolean,
duration:Number
});
//过度时间:
const ition=ref(1);
//左边的距离
const leftVal=ref(0);
//当前图片索引:
const index = ref(0);
//左边按钮
const prev = () => {
if(index.value==0){
index.value = lang.value - 1;
ition.value=0// 将过渡时间变成0,瞬间位移到最后一张图
leftVal.value=lang.value*props.width// 瞬间移动
setTimeout(()=>{ // 通过延时障眼法,归原过渡时间,执行真正的“上一张”函数
ition.value=0.8
leftVal.value -= props.width
},ition.value*1000)
}else{
index.value--;
ition.value=0.8
leftVal.value -= props.width
}
};
//右边按钮:
const next = () => {
if(index.value==lang.value-1){
index.value = 0;
ition.value=0.8
leftVal.value+=props.width
setTimeout(()=>{
ition.value=0
leftVal.value=0
},ition.value*1000)
}else{
index.value++;
ition.value=0.8
leftVal.value+=props.width
}
};
// 计算图片列表的长度
const lang = computed(() => {
return props.list.length;
});
//点击指示器:
const clickindex = (i) => {
index.value = i;
};
// 封装一个自动轮播的函数
const timer = ref(null);
const autoplayFn = () => {
// 防止触发多个定时任务
clearInterval(timer.value);
timer.value = setInterval(() => {
if(index.value==lang.value-1){
index.value = 0;
ition.value=0.8
leftVal.value+=props.width
setTimeout(()=>{
ition.value=0
leftVal.value=0
},ition.value*1000)
}else{
index.value++;
ition.value=0.8
leftVal.value+=props.width
}
}, props.duration * 1000);
};
// 侦听器也可以侦听props的数据
//导入鼠标位置控制插件
import { useMouseInElement } from '@vueuse/core'
const target = ref(null)
//isOutside 鼠标是否在目标target外面:
const { isOutside } = useMouseInElement(target)
watch( isOutside,() => {
//如果鼠标移入到盒子里面 ,关闭自动轮播
//鼠标 不在盒子内 可以开启自动轮播
// 轮播图长度大于1并且标志位是放开的
if (lang.value > 1 && props.autoplay && isOutside.value) {
autoplayFn();
}else{
clearInterval(timer.value);
}
},
{ immediate: true }
);
// 组件销毁,清理定时器
onUnmounted(() => {
clearInterval(timer)
})
</script>
<template>
<div
class="xtx-carousel"
:style="{ height: height + 'px', width: width + 'px' }"
ref="target"
>
<ul class="carousel-body" :style="{width: width*(lang+1) +'px',left:`-${leftVal}px`,transition:`${ition}s`}" >
<!-- 图片 -->
<li
class="carousel-item"
v-for="(item, i) in list"
:key="i"
:style="{ width: width + 'px' }"
>
<!-- <RouterLink to="/"> -->
<img :src="item.imgUrl" alt="" />
<!-- </RouterLink> -->
</li>
<!-- 复制第一张放到最后,以实现无缝无线循环滚动效果 -->
<li class="carousel-item" :style="{width: width +'px'}">
<img :src="list[0].imgUrl" alt="">
</li>
</ul>
<!-- 左右箭头 -->
<a href="javascript:;" class="carousel-btn prev" @click="prev"
><el-icon><ArrowLeftBold /></el-icon
></a>
<a href="javascript:;" class="carousel-btn next" @click="next"
><el-icon><ArrowRightBold /></el-icon
></a>
<!-- 指示小圆点 -->
<div class="carousel-indicator">
<span
v-for="(item, i) in list"
:key="i"
:class="{ active: index === i }"
@click="clickindex(i)"
></span>
</div>
</div>
</template>
<style scoped lang="scss">
.xtx-carousel {
position: relative;
overflow: hidden;
.carousel {
&-body {
position: absolute;
height: 100%;
}
&-item {
float: left;
height: 100%;
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: 45%;
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>