ct/app/components/index/Carousel.vue
2025-10-08 14:37:58 +08:00

285 lines
5.8 KiB
Vue

<template>
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators" style="background-color: rgba(0,0,0,0.08);">
<li
v-for="(item, index) in carouselItems"
:key="index"
:class="{ active: index === currentSlide }"
:data-slide-to="index"
:data-target="`#carousel-example-generic`"
@click="goToSlide(index)"
/>
</ol>
<!-- Wrapper for slides -->
<div class="carousel-inner" role="listbox">
<div
v-for="(item, index) in carouselItems"
:key="index"
:class="{ active: index === currentSlide }"
class="item"
>
<img
:alt="item.alt"
:src="item.image"
style="width: 100%;"
>
<div v-if="item.caption" class="carousel-caption">
<h2>{{ item.caption.title }}</h2>
<ul v-if="item.caption.links" class="list-unstyled hidden-xs hidden-sm">
<li v-for="(link, linkIndex) in item.caption.links" :key="linkIndex">
<a :href="link.href" :target="link.target">
<img :alt="link.alt" :src="link.image">
</a>
<span/>{{ link.text }}
</li>
</ul>
</div>
</div>
</div>
<!-- Controls -->
<a
class="left carousel-control"
data-slide="prev"
href="#carousel-example-generic"
role="button"
@click.prevent="previousSlide"
>
<span aria-hidden="true" class="glyphicon glyphicon-chevron-left"/>
<span class="sr-only">Previous</span>
</a>
<a
class="right carousel-control"
data-slide="next"
href="#carousel-example-generic"
role="button"
@click.prevent="nextSlide"
>
<span aria-hidden="true" class="glyphicon glyphicon-chevron-right"/>
<span class="sr-only">Next</span>
</a>
</div>
</template>
<script lang="ts" setup>
import {ref, onMounted, onUnmounted} from 'vue'
// 响应式数据
const currentSlide = ref(2) // 默认显示第三张图片
const autoPlayInterval = ref<NodeJS.Timeout | null>(null)
// 轮播图数据
const carouselItems = [
{
image: '/www.yuxiit.com/img/yuxiupdata/banner_2021_1.png',
alt: '成本降低,效率更高'
},
{
image: '/www.yuxiit.com/img/yuxiupdata/banner_2021_2.png',
alt: '成本降低,效率更高'
},
{
image: '/www.yuxiit.com/img/yuxiupdata/index23.png',
alt: '共享单车最佳拍档',
}
]
// 方法
const goToSlide = (index: number) => {
currentSlide.value = index
}
const nextSlide = () => {
currentSlide.value = (currentSlide.value + 1) % carouselItems.length
}
const previousSlide = () => {
currentSlide.value = currentSlide.value === 0 ? carouselItems.length - 1 : currentSlide.value - 1
}
const startAutoPlay = () => {
autoPlayInterval.value = setInterval(() => {
nextSlide()
}, 5000) // 5秒自动切换
}
const stopAutoPlay = () => {
if (autoPlayInterval.value) {
clearInterval(autoPlayInterval.value)
autoPlayInterval.value = null
}
}
// 生命周期
onMounted(() => {
startAutoPlay()
})
onUnmounted(() => {
stopAutoPlay()
})
</script>
<style scoped>
.carousel {
position: relative;
}
.carousel-inner {
position: relative;
width: 100%;
overflow: hidden;
}
.carousel-inner > .item {
position: relative;
display: none;
transition: 0.6s ease-in-out left;
}
.carousel-inner > .item.active {
display: block;
}
.carousel-inner > .item > img {
display: block;
width: 100%;
height: auto;
}
.carousel-indicators {
position: absolute;
bottom: 10px;
left: 50%;
z-index: 15;
width: 60%;
padding-left: 0;
margin-left: -30%;
text-align: center;
list-style: none;
}
.carousel-indicators li {
display: inline-block;
width: 10px;
height: 10px;
margin: 1px;
text-indent: -999px;
cursor: pointer;
background-color: #000 \9;
background-color: rgba(0, 0, 0, 0);
border: 1px solid #fff;
border-radius: 10px;
}
.carousel-indicators .active {
width: 12px;
height: 12px;
margin: 0;
background-color: #fff;
}
.carousel-control {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 15%;
font-size: 20px;
color: #fff;
text-align: center;
text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
background-color: rgba(0, 0, 0, 0);
filter: alpha(opacity=50);
opacity: .5;
}
.carousel-control.right {
right: 0;
left: auto;
}
.carousel-control:hover,
.carousel-control:focus {
color: #fff;
text-decoration: none;
filter: alpha(opacity=70);
opacity: .7;
}
.carousel-control .icon-prev,
.carousel-control .icon-next,
.carousel-control .glyphicon-chevron-left,
.carousel-control .glyphicon-chevron-right {
position: absolute;
top: 50%;
z-index: 5;
display: inline-block;
margin-top: -10px;
}
.carousel-control .icon-prev,
.carousel-control .glyphicon-chevron-left {
left: 50%;
margin-left: -10px;
}
.carousel-control .icon-next,
.carousel-control .glyphicon-chevron-right {
right: 50%;
margin-right: -10px;
}
.carousel-caption {
position: absolute;
right: 15%;
bottom: 20px;
left: 15%;
z-index: 10;
padding-top: 20px;
padding-bottom: 20px;
color: #fff;
text-align: center;
text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
}
.carousel-caption h2 {
font-size: 2.5em;
margin-bottom: 20px;
}
.carousel-caption .list-unstyled {
list-style: none;
padding: 0;
margin: 0;
}
.carousel-caption .list-unstyled li {
display: inline-block;
margin: 0 10px;
vertical-align: top;
}
.carousel-caption .list-unstyled a {
color: #fff;
text-decoration: none;
}
.carousel-caption .list-unstyled img {
width: 50px;
height: 50px;
margin-bottom: 10px;
}
@media (max-width: 768px) {
.carousel-caption h2 {
font-size: 1.5em;
}
.carousel-caption .list-unstyled {
display: none;
}
}
</style>