feat: 轮播图组件

This commit is contained in:
2026-05-14 15:10:57 +08:00
parent 5668ec3747
commit 89ea954743
9 changed files with 361 additions and 400 deletions

View File

@@ -0,0 +1,181 @@
<template>
<section class="carousel-container" aria-label="Featured content">
<KagolCarousel
v-model="activePage"
class="home-carousel"
:autoplay="isAutoplayEnabled"
:interval="5000"
>
<article v-for="slide in slides" :key="slide.id" class="carousel-slide">
<img class="carousel-image" :src="slide.image" :alt="slide.alt" />
</article>
<template #pagination="{ prevPage, nextPage }">
<nav class="carousel-pagination" aria-label="Carousel pagination">
<button
class="carousel-pagination-button carousel-pagination-button-prev"
type="button"
aria-label="Previous slide"
@click="prevPage"
>
<span
class="carousel-pagination-arrow carousel-pagination-arrow-prev"
></span>
</button>
<button
class="carousel-pagination-button carousel-pagination-button-next"
type="button"
aria-label="Next slide"
@click="nextPage"
>
<span
class="carousel-pagination-arrow carousel-pagination-arrow-next"
></span>
</button>
</nav>
</template>
<template #indicator></template>
</KagolCarousel>
</section>
</template>
<script setup lang="ts">
import { Carousel as KagolCarousel } from '@kagol/vue-carousel'
import '@kagol/vue-carousel/dist/style.css'
import { onMounted, shallowRef } from 'vue'
import mainBanner01 from '../../../assets/images/home/mainbanner01.jpg'
import mainBanner02 from '../../../assets/images/home/mainbanner02.jpg'
const activePage = shallowRef(1)
const isAutoplayEnabled = shallowRef(false)
const slides = [
{
id: 'aida',
image: mainBanner01,
alt: 'AiDA product banner'
},
{
id: 'mixi',
image: mainBanner02,
alt: 'Mixi product banner'
}
] as const
onMounted(() => {
isAutoplayEnabled.value = true
})
</script>
<style scoped>
.carousel-container {
width: 100%;
overflow: hidden;
background: #070b14;
}
.home-carousel {
width: 100%;
}
.carousel-slide {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
min-height: 360px;
max-height: 680px;
overflow: hidden;
background: #070b14;
}
.carousel-image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.carousel-pagination {
position: absolute;
right: 0;
bottom: 0;
z-index: 2;
display: flex;
flex-direction: column;
width: 70px;
height: 140px;
transform: translateX(100%);
transition: transform 0.28s ease;
will-change: transform;
}
.carousel-container:hover .carousel-pagination {
transform: translateX(0);
}
.carousel-pagination-button {
position: relative;
display: flex;
flex: 1 1 0;
align-items: center;
justify-content: center;
width: 100%;
padding: 0;
border: 0;
color: #ffffff;
background: #65090c;
cursor: pointer;
appearance: none;
transition: background-color 0.2s ease;
}
.carousel-pagination-button:hover {
background: rgba(255, 255, 255, 0.75);
}
.carousel-pagination-button:focus-visible {
position: relative;
z-index: 1;
outline: 2px solid #ffffff;
outline-offset: -6px;
}
.carousel-pagination-arrow {
position: absolute;
top: 50%;
left: 50%;
display: block;
box-sizing: border-box;
width: 20px;
height: 20px;
border-top: 2.5px solid currentColor;
border-right: 2.5px solid currentColor;
}
.carousel-pagination-arrow-prev {
transform: translate(-50%, -50%) rotate(225deg);
}
.carousel-pagination-arrow-next {
transform: translate(-50%, -50%) rotate(45deg);
}
:deep(.xui-carousel) {
width: 100%;
}
:deep(.xui-carousel-item-container) {
height: 100%;
}
@media (max-width: 768px) {
.carousel-slide {
min-height: 320px;
}
.carousel-pagination-arrow {
width: 18px;
height: 18px;
}
}
</style>

95
src/pages/home/index.vue Normal file
View File

@@ -0,0 +1,95 @@
<template>
<main class="home-page">
<HomeCarousel />
<section class="home-links" aria-label="Site pages">
<RouterLink
v-for="page in pageLinks"
:key="page.to"
class="home-link"
:to="page.to"
>
{{ page.label }}
</RouterLink>
</section>
</main>
</template>
<script setup lang="ts">
import { useHead } from '@unhead/vue'
import { RouterLink } from 'vue-router'
import HomeCarousel from './components/Carousel.vue'
const pageLinks = [
{ label: 'About', to: '/about' },
{ label: 'Products', to: '/products' },
{ label: 'Contact', to: '/contact' },
] as const
useHead({
title: 'Home | Code Create',
meta: [
{
name: 'description',
content: 'Code Create home page rendered with Vite SSG.',
},
],
})
</script>
<style scoped>
.home-page {
/* width: 100%; */
/* min-height: 100svh; */
/* background: #ffffff; */
}
.home-links {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
padding: 32px 20px 48px;
}
.home-link {
min-width: 112px;
padding: 10px 16px;
border: 1px solid #d9dde6;
border-radius: 6px;
color: #1d2430;
background: #ffffff;
font-size: 15px;
line-height: 1.2;
text-align: center;
text-decoration: none;
box-sizing: border-box;
transition:
border-color 0.2s,
color 0.2s,
box-shadow 0.2s;
}
.home-link:hover,
.home-link:focus-visible,
.home-link.router-link-active {
border-color: #2f6df6;
color: #2f6df6;
box-shadow: 0 8px 24px rgba(36, 55, 92, 0.12);
}
.home-link:focus-visible {
outline: 2px solid #2f6df6;
outline-offset: 2px;
}
@media (max-width: 640px) {
.home-links {
padding: 24px 16px 40px;
}
.home-link {
flex: 1 1 calc(50% - 12px);
}
}
</style>