qs_xinchun2026_h5/components/LoadingComponent.vue

222 lines
4.5 KiB
Vue
Raw Permalink 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.

<script setup>
import { ref, onMounted, computed } from 'vue'
// 组件属性
const props = defineProps({
// 是否显示
visible: {
type: Boolean,
default: true
}
})
// 组件事件
const emit = defineEmits(['loaded', 'start'])
// 加载进度
const loadingProgress = ref(0)
// 是否加载完成
const isLoadingComplete = ref(false)
// 是否显示开始按钮
const showStartButton = ref(false)
// 生成带时间戳的图片URL避免缓存
const generateImageUrl = (name) => {
const url = new URL(`/static/bg/${name}.jpg`, import.meta.url)
// 添加时间戳参数避免浏览器缓存
return url.href
}
// 计算开始按钮是否可见
const startButtonVisible = computed(() => {
return isLoadingComplete.value && showStartButton.value
})
// 加载图片函数
const loadImages = async () => {
// 图片名称数组
const bgImageNames = [
'bg1',
'bg2',
'bg3',
'bg4',
'bg5',
'bg_finish',
'bg_main'
]
// 生成图片URL数组
const bgImages = bgImageNames.map(name => generateImageUrl(name))
const totalImages = bgImages.length
let loadedImages = 0
// 加载每张图片
for (const imagePath of bgImages) {
try {
await loadImage(imagePath)
loadedImages++
// 更新加载进度
const progress = Math.round((loadedImages / totalImages) * 100)
loadingProgress.value = progress
// 模拟加载延迟,使进度条动画更流畅
await new Promise(resolve => setTimeout(resolve, 100))
} catch (error) {
console.error('加载图片失败:', imagePath, error)
// 即使加载失败,也继续加载其他图片
loadedImages++
loadingProgress.value = Math.round((loadedImages / totalImages) * 100)
}
}
// 加载完成
isLoadingComplete.value = true
loadingProgress.value = 100
// 延迟显示开始按钮让用户看到100%的进度
setTimeout(() => {
showStartButton.value = true
// 通知父组件加载完成
emit('loaded')
}, 500)
}
// 单个图片加载函数
const loadImage = (src) => {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = resolve
img.onerror = reject
img.src = src
})
}
// 点击开始按钮
const handleStart = () => {
emit('start')
}
// 阻止 iOS 滚动穿透
const handleTouchMove = (e) => {
e.preventDefault()
}
// 组件挂载后开始加载图片
onMounted(() => {
loadImages()
})
</script>
<template>
<div v-if="visible" class="loading-container" @touchmove="handleTouchMove">
<!-- 背景图片 -->
<div class="loading-bg">
<img src="/static/loading/loading_bg.jpg" alt="加载背景" class="bg-image" />
</div>
<!-- 进度条区域 -->
<div v-if="!startButtonVisible" class="progress-container">
<div class="progress-bar">
<div class="progress-fill" :style="{ width: `${loadingProgress}%` }"></div>
</div>
<div class="progress-text">{{ loadingProgress }}%</div>
</div>
<!-- 开始按钮 -->
<div v-if="startButtonVisible" class="start-button" @click="handleStart">
<img src="/static/loading/btn_start.png" alt="开始" class="start-btn-image" />
</div>
</div>
</template>
<style scoped>
.loading-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
background-color: #fd4336;
}
.loading-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.bg-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.progress-container {
position: absolute;
bottom: 30vh;
width: 80%;
max-width: 500rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.progress-bar {
width: 100%;
height: 20rpx;
background-color: rgba(255, 255, 255, 0.3);
border-radius: 10rpx;
overflow: hidden;
margin-bottom: 20rpx;
}
.progress-fill {
height: 100%;
background-color: #FFD700;
border-radius: 10rpx;
transition: width 0.3s ease;
}
.progress-text {
font-size: 36rpx;
font-weight: bold;
color: #FFD700;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.5);
}
.start-button {
position: absolute;
bottom: 20vh;
width: 496rpx;
height: 97rpx;
cursor: pointer;
animation: pulse 1.5s infinite;
}
.start-btn-image {
width: 100%;
height: 100%;
object-fit: contain;
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
</style>