217 lines
4.4 KiB
Vue
217 lines
4.4 KiB
Vue
<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')
|
||
}
|
||
|
||
// 组件挂载后开始加载图片
|
||
onMounted(() => {
|
||
loadImages()
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div v-if="visible" class="loading-container">
|
||
<!-- 背景图片 -->
|
||
<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> |