This commit is contained in:
wangzzpeng
2026-09-28 09:27:51 +08:00
parent 7bc84bbe5e
commit 6eb2bfcbfd
25 changed files with 2887 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import type { BannerVo } from '@/types/business/home'
interface Props {
banners: BannerVo[]
}
const props = defineProps<Props>()
/** 仅保留启用且带图的轮播项,按后端 sort 升序 */
const slides = computed(() =>
props.banners
.filter((item) => item.enabled !== false && !!item.imageUrl)
.slice()
.sort((prev, next) => (prev.sort ?? 0) - (next.sort ?? 0)),
)
const current = ref(0)
let timer: number | undefined
function stop(): void {
if (timer !== undefined) {
window.clearInterval(timer)
timer = undefined
}
}
function go(index: number): void {
const total = slides.value.length
if (total === 0) return
current.value = (index + total) % total
}
function start(): void {
stop()
if (slides.value.length <= 1) return
timer = window.setInterval(() => go(current.value + 1), 5000)
}
watch(
() => slides.value.length,
() => {
current.value = 0
start()
},
)
onMounted(start)
onBeforeUnmount(stop)
</script>
<template>
<section v-if="slides.length" class="home-banner">
<img
v-for="(slide, index) in slides"
v-show="index === current"
:key="slide.id ?? index"
class="home-banner__img"
:src="slide.imageUrl ?? ''"
:alt="`轮播图 ${index + 1}`"
>
<template v-if="slides.length > 1">
<button
class="home-banner__arrow home-banner__arrow--prev"
type="button"
aria-label="上一张"
@click="go(current - 1)"
>
‹
</button>
<button
class="home-banner__arrow home-banner__arrow--next"
type="button"
aria-label="下一张"
@click="go(current + 1)"
>
›
</button>
</template>
</section>
</template>
<style lang="less" scoped>
.home-banner {
position: relative;
height: 240px;
overflow: hidden;
border-radius: @radius-lg;
background: @bg-color;
box-shadow: @shadow-base;
&__img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
&__arrow {
position: absolute;
top: 50%;
width: 32px;
height: 32px;
transform: translateY(-50%);
border-radius: @radius-round;
background: rgba(31, 39, 51, 0.35);
color: @white;
font-size: @font-size-xl;
line-height: 1;
opacity: 0;
transition: opacity 0.2s;
&--prev {
left: @spacing-base;
}
&--next {
right: @spacing-base;
}
}
&:hover &__arrow {
opacity: 1;
}
}
</style>