This commit is contained in:
yixu
2025-12-19 11:21:04 +08:00
commit 258e14e27c
82 changed files with 5371 additions and 0 deletions

View File

@@ -0,0 +1,359 @@
<template>
<ModalTransition class="game-swiper" :show="show">
<div class="scene-item item-1" @click="handleGoHome">
<img src="../assets/images/new/go-home.png" alt="回到首页">
</div>
<div class="scene-item item-2">
<img src="../assets/images/new/music.png" alt="音乐">
</div>
<div class="confirm-layout">
<div class="scene-item item-3" @click="handleConfirmClick">
<img src="../assets/images/new/confirm-btn.png" alt="确定">
</div>
</div>
<div class="swiper-page">
<div class="carousel-container">
<div
class="carousel-wrapper"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
>
<div
class="carousel-track"
:style="{ transform: `translateX(calc(-${currentIndex * 100}% + ${currentIndex * 60}px))`, transition: isTransitioning ? 'transform 0.3s ease' : 'none' }"
>
<div
v-for="(slide, index) in slides"
:key="index"
:class="['carousel-slide', { active: currentIndex === index }]"
>
<img :src="slide.image" :alt="slide.title" />
</div>
</div>
</div>
<!-- 指示器 -->
<div class="carousel-indicators">
<span
v-for="(slide, index) in slides"
:key="index"
:class="['indicator', { active: currentIndex === index }]"
@click="goToSlide(index)"
></span>
</div>
</div>
</div>
</ModalTransition>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import ModalTransition from "./ModalTransition.vue"
import globalToastEvent, { ToastType } from '../globalToastEvent';
const props = defineProps({
show: false,
})
const emit = defineEmits(['update:show'])
const handleGoHome = () => {
emit('close')
}
// 轮播图数据
const slides = ref([
{
image: new URL('../assets/images/new/slider1.png', import.meta.url).href,
title: '轮播图1',
link: '/home' // 点击跳转的路由
},
{
image: new URL('../assets/images/new/slider1.png', import.meta.url).href,
title: '轮播图2',
link: '/lottery'
},
{
image: new URL('../assets/images/new/slider1.png', import.meta.url).href,
title: '轮播图3',
link: '/address'
}
])
const currentIndex = ref(0)
const startX = ref(0)
const moveX = ref(0)
const isDragging = ref(false)
const isTransitioning = ref(true)
let autoPlayTimer = null
// 触摸开始
const handleTouchStart = (e) => {
startX.value = e.touches[0].clientX
isDragging.value = true
isTransitioning.value = false
stopAutoPlay()
}
// 触摸移动
const handleTouchMove = (e) => {
if (!isDragging.value) return
moveX.value = e.touches[0].clientX - startX.value
}
// 触摸结束
const handleTouchEnd = () => {
if (!isDragging.value) return
isTransitioning.value = true
const threshold = 50 // 滑动阈值
if (moveX.value > threshold) {
// 向右滑动 - 上一张
prevSlide()
} else if (moveX.value < -threshold) {
// 向左滑动 - 下一张
nextSlide()
}
isDragging.value = false
moveX.value = 0
// startAutoPlay()
}
// 上一张
const prevSlide = () => {
currentIndex.value = currentIndex.value > 0
? currentIndex.value - 1
: slides.value.length - 1
}
// 下一张
const nextSlide = () => {
currentIndex.value = currentIndex.value < slides.value.length - 1
? currentIndex.value + 1
: 0
}
// 跳转到指定幻灯片
const goToSlide = (index) => {
isTransitioning.value = true
currentIndex.value = index
stopAutoPlay()
startAutoPlay()
}
const hasVisitedBefore = localStorage.getItem('hasVisitedGameSwiper');
const handleConfirmClick = () => {
const slide = slides.value?.[currentIndex.value]
if (!slide) return
handleSlideClick(slide)
}
const handleSlideClick = (slide) => {
if (!hasVisitedBefore) {
localStorage.setItem('hasVisitedGameSwiper', 'true');
globalToastEvent.emit(ToastType.SHOW_GAMEDEMO)
globalToastEvent.emit(ToastType.SHOW_GAMEPAGE)
} else {
globalToastEvent.emit(ToastType.SHOW_GAMEPAGE)
}
}
// 自动播放
const startAutoPlay = () => {
autoPlayTimer = setInterval(() => {
nextSlide()
}, 3000) // 每3秒切换一次
}
// 停止自动播放
const stopAutoPlay = () => {
if (autoPlayTimer) {
clearInterval(autoPlayTimer)
autoPlayTimer = null
}
}
// 生命周期
onMounted(() => {
// startAutoPlay()
})
onUnmounted(() => {
stopAutoPlay()
})
</script>
<style scoped>
.scene-item {
position: fixed;
cursor: pointer;
transition: all 0.4s ease;
overflow: hidden;
animation: float 4s ease-in-out infinite;
}
.scene-item:hover {
transform: scale(1.05);
}
.scene-item img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.item-1 {
width: 14vw;
height: 14vw;
top: 8vw;
left: 2vw;
animation-delay: 0s;
}
.item-2 {
width: 12vw;
height: 12vw;
top: 8vw;
right: 2vw;
animation-delay: 0s;
}
.item-3 {
width: 46vw;
bottom: 14vw;
animation-delay: 0s;
}
.confirm-layout {
display: flex;
justify-content: center;
}
.swiper-page {
width: 100%;
min-height: 100vh;
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
box-sizing: border-box;
background-image: url('../assets/images/new/swiper-page-bg.png');
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.carousel-container {
width: 100%;
max-width: 100vw;
position: relative;
padding: 0 20px;
box-sizing: border-box;
}
.carousel-wrapper {
width: 80vw;
overflow: visible;
position: relative;
touch-action: pan-y;
}
.carousel-track {
display: flex;
flex-direction: row;
width: 100%;
padding: 20px 0;
}
.carousel-slide {
min-width: calc(100% - 160px);
width: calc(100% - 160px);
margin: 0 20px;
flex-shrink: 0;
cursor: pointer;
user-select: none;
transition: all 0.3s ease;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transform: scale(0.85);
opacity: 0.5;
filter: grayscale(60%) brightness(0.7);
}
.carousel-slide.active {
transform: scale(1);
opacity: 1;
filter: grayscale(0%) brightness(1);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
z-index: 2;
}
.carousel-slide img {
width: 100%;
height: auto;
display: block;
object-fit: cover;
pointer-events: none;
}
/* 指示器 */
.carousel-indicators {
position: absolute;
bottom: -8vw;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 2vw;
padding: 2vw 4vw;
background: rgba(0, 0, 0, 0.3);
border-radius: 4vw;
backdrop-filter: blur(4px);
}
.indicator {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
cursor: pointer;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.indicator:hover {
background: rgba(255, 255, 255, 0.8);
transform: scale(1.2);
}
.indicator.active {
background: #fff;
width: 28px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
/* 移动端适配 */
@media (max-width: 768px) {
.game-page {
padding: 10px;
}
.carousel-container {
padding: 0 10px;
}
.carousel-slide {
min-width: calc(100% - 12vw);
width: calc(100% - 12vw);
margin: 0 10px;
border-radius: 8px;
}
.carousel-track {
padding: 10px 0;
}
}
</style>