Files
gym-manage/gym-manage-uniapp/components/index/BannerSwiper.vue
T

218 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="banner-container">
<swiper
class="banner-swiper"
:circular="true"
:autoplay="true"
:interval="4000"
:duration="500"
:indicator-dots="false"
@change="onSwiperChange"
>
<swiper-item v-for="(banner, index) in banners" :key="index">
<view class="banner-content" @click="previewImage(index)">
<!-- 添加 lazy-load 属性实现懒加载 -->
<image
:src="banner.image"
mode="aspectFill"
class="banner-image"
lazy-load
:show-menu-by-longpress="false"
@load="onImageLoad(index)"
@error="onImageError(index)"
/>
<view class="banner-overlay"></view>
<view class="banner-text">
<text class="banner-title">{{ banner.title }}</text>
<text class="banner-subtitle">{{ banner.subtitle }}</text>
<text class="banner-desc">{{ banner.desc }}</text>
</view>
<!-- 可选添加加载占位符 -->
<view v-if="!imageLoaded[index]" class="image-placeholder">
<view class="loading-spinner"></view>
</view>
</view>
</swiper-item>
</swiper>
<view class="banner-dots">
<view
v-for="(_, index) in banners"
:key="index"
:class="['dot', { active: currentIndex === index }]"
></view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const banners = [
{
image: 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=800&q=80',
title: '突破自我',
subtitle: '超越极限',
desc: '科学训练 · 遇见更好的自己'
},
{
image: 'https://images.unsplash.com/photo-1517836357463-d25dfeac3438?w=800&q=80',
title: '专业指导',
subtitle: '高效训练',
desc: '私人定制 · 专属健身方案'
},
{
image: 'https://images.unsplash.com/photo-1571019614242-c5c5dee9f50b?w=800&q=80',
title: '健康生活',
subtitle: '从这里开始',
desc: '全方位 · 打造完美体态'
}
]
const currentIndex = ref(0)
// 记录每张图片的加载状态
const imageLoaded = ref(banners.map(() => false))
const onSwiperChange = (e) => {
currentIndex.value = e.detail.current
}
const previewImage = (index) => {
const urls = banners.map(banner => banner.image)
uni.previewImage({
urls: urls,
current: urls[index],
indicator: 'default',
loop: true
})
}
// 图片加载成功回调
const onImageLoad = (index) => {
imageLoaded.value[index] = true
console.log(`图片 ${index} 加载完成`)
}
// 图片加载失败回调
const onImageError = (index) => {
console.error(`图片 ${index} 加载失败`)
// 可选:设置默认占位图
// banners[index].image = '默认图片URL'
}
</script>
<style lang="scss" scoped>
.banner-container {
position: relative;
z-index: 2;
width: 100%;
}
.banner-swiper {
width: 100%;
height: 480rpx;
}
.banner-content {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.banner-image {
width: 100%;
height: 100%;
}
/* 添加图片占位符样式 */
.image-placeholder {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.loading-spinner {
width: 60rpx;
height: 60rpx;
border: 4rpx solid rgba(255, 255, 255, 0.3);
border-top: 4rpx solid #7AB5CC;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.banner-overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 2; /* 确保遮罩层在占位符上面 */
}
/* 其余样式保持不变 */
.banner-text {
position: absolute;
left: 36rpx;
top: 50%;
transform: translateY(-50%);
z-index: 3;
}
.banner-title {
display: block;
font-size: 48rpx;
font-weight: 800;
color: #ffffff;
margin-bottom: 8rpx;
text-shadow: 0 4rpx 16rpx rgba(80, 150, 190, 0.4);
}
.banner-subtitle {
display: block;
font-size: 56rpx;
font-weight: 800;
color: #E0F0FA;
margin-bottom: 16rpx;
text-shadow: 0 4rpx 16rpx rgba(80, 150, 190, 0.4);
}
.banner-desc {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.85);
}
.banner-dots {
display: flex;
justify-content: center;
gap: 16rpx;
margin-top: -100rpx;
position: relative;
z-index: 3;
}
.dot {
width: 48rpx;
height: 8rpx;
border-radius: 9999rpx;
background: #D0E4EE;
transition: all 0.3s ease;
}
.dot.active {
width: 64rpx;
background: linear-gradient(90deg, #7AB5CC, #9CCFDF);
}
</style>