fix: 加载优化
This commit is contained in:
@@ -18,6 +18,94 @@
|
|||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 全局样式 */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载动画样式 */
|
||||||
|
.loader-container {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #fff;
|
||||||
|
z-index: 1000;
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-title {
|
||||||
|
font-size: clamp(1.5rem, 3vw, 2.5rem);
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-subtitle {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-logo {
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pulse-box {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: #000;
|
||||||
|
display: inline-block;
|
||||||
|
transform-origin: center;
|
||||||
|
animation: pulse 1.2s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1) rotate(0deg);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.2) rotate(45deg);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1) rotate(90deg);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-text {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-progress-bar {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 400px;
|
||||||
|
height: 8px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader-progress {
|
||||||
|
height: 100%;
|
||||||
|
width: 0%;
|
||||||
|
background: #000;
|
||||||
|
transition: width 0.3s ease-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -34,177 +122,36 @@
|
|||||||
<div id="progress-bar" class="loader-progress"></div>
|
<div id="progress-bar" class="loader-progress"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 加载进度脚本:放在 main.ts 之前,保证先执行 -->
|
||||||
|
<script>
|
||||||
|
// 立即执行函数改为更简单的写法,减少解析时间
|
||||||
|
(function(){
|
||||||
|
const bar = document.getElementById('progress-bar');
|
||||||
|
const text = document.getElementById('progress-text');
|
||||||
|
let progress = 0;
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
progress = Math.min(progress + 2 + Math.random() * 3, 95);
|
||||||
|
bar.style.width = progress + '%';
|
||||||
|
text.textContent = Math.floor(progress) + '%';
|
||||||
|
if(progress < 95) requestAnimationFrame(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
window.finishLoading = function() {
|
||||||
|
bar.style.width = '100%';
|
||||||
|
text.textContent = '100%';
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById('loader').style.opacity = '0';
|
||||||
|
setTimeout(() => document.getElementById('loader').remove(), 500);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
|
||||||
/* 全局样式 */
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 加载动画样式 */
|
|
||||||
.loader-container {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: #fff;
|
|
||||||
z-index: 1000;
|
|
||||||
transition: opacity 0.5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-title {
|
|
||||||
font-size: clamp(1.5rem, 3vw, 2.5rem);
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
letter-spacing: -0.02em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-subtitle {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: #555;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-logo {
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pulse-box {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
background: #000;
|
|
||||||
display: inline-block;
|
|
||||||
transform-origin: center;
|
|
||||||
animation: pulse 1.2s infinite ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse {
|
|
||||||
0% {
|
|
||||||
transform: scale(1) rotate(0deg);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: scale(1.2) rotate(45deg);
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: scale(1) rotate(90deg);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-text {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-progress-bar {
|
|
||||||
width: 90%;
|
|
||||||
max-width: 400px;
|
|
||||||
height: 8px;
|
|
||||||
background: #f0f0f0;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader-progress {
|
|
||||||
height: 100%;
|
|
||||||
width: 0%;
|
|
||||||
background: #000;
|
|
||||||
transition: width 0.3s ease-out;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
// 加载动画逻辑
|
|
||||||
// document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
const loader = document.getElementById('loader');
|
|
||||||
const progressBar = document.getElementById('progress-bar');
|
|
||||||
const progressText = document.getElementById('progress-text');
|
|
||||||
|
|
||||||
let progress = 0;
|
|
||||||
let loadingInterval = null;
|
|
||||||
let isVueReady = false;
|
|
||||||
|
|
||||||
// 注册全局事件监听器,用于接收Vue的加载完成信号(生产环境没有用,所以放到app.vue处理)
|
|
||||||
window.addEventListener('vue-ready', function () {
|
|
||||||
isVueReady = true;
|
|
||||||
completeLoading();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 开始模拟加载
|
|
||||||
function startLoading() {
|
|
||||||
const targetProgress = 95;
|
|
||||||
const intervalTime = 50; // 50毫秒更新一次
|
|
||||||
|
|
||||||
// 计算每次递增的进度值,使用更快的初始速度
|
|
||||||
let increment = calculateIncrement();
|
|
||||||
|
|
||||||
|
|
||||||
// 开始加载动画
|
|
||||||
loadingInterval = setInterval(() => {
|
|
||||||
if (progress>=targetProgress)
|
|
||||||
{
|
|
||||||
increment=0;
|
|
||||||
}
|
|
||||||
progress += increment;
|
|
||||||
|
|
||||||
// 如果进度达到95%或者Vue已经准备好
|
|
||||||
if (isVueReady) {
|
|
||||||
// progress = 100;
|
|
||||||
clearInterval(loadingInterval);
|
|
||||||
completeLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateProgress(progress);
|
|
||||||
}, intervalTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算动态递增速率,初始较快,后期较慢
|
|
||||||
function calculateIncrement() {
|
|
||||||
// 如果已经检测到Vue正在加载,加快进度
|
|
||||||
if (window.Vue) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 首次访问海外地址可能较慢
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新进度条和文本
|
|
||||||
function updateProgress(value) {
|
|
||||||
progressBar.style.width = `${value}%`;
|
|
||||||
progressText.textContent = `${Math.round(value)}%`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 完成加载并隐藏动画
|
|
||||||
function completeLoading() {
|
|
||||||
// 确保进度是100%
|
|
||||||
// updateProgress(100);
|
|
||||||
|
|
||||||
// 淡出加载动画
|
|
||||||
setTimeout(() => {
|
|
||||||
loader.style.opacity = '0';
|
|
||||||
setTimeout(() => {
|
|
||||||
loader.style.display = 'none';
|
|
||||||
}, 500);
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 启动加载动画
|
|
||||||
startLoading();
|
|
||||||
// });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script async type="module" src="/src/main.ts"></script>
|
<script async type="module" src="/src/main.ts"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,27 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
onMounted(() => {
|
|
||||||
// completeLoading();
|
|
||||||
// const event = new Event('vue-ready');
|
|
||||||
// window.dispatchEvent(event);
|
|
||||||
completeLoading();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 完成加载并隐藏动画
|
|
||||||
function completeLoading() {
|
|
||||||
const loader = document.getElementById('loader');
|
|
||||||
const progressBar = document.getElementById('progress-bar');
|
|
||||||
const progressText = document.getElementById('progress-text');
|
|
||||||
// 确保进度是100%
|
|
||||||
progressBar!.style.width = `${100}%`;
|
|
||||||
progressText!.textContent = `${Math.round(100)}%`;
|
|
||||||
// 淡出加载动画
|
|
||||||
setTimeout(() => {
|
|
||||||
//loader!.style.opacity = '100';
|
|
||||||
setTimeout(() => {
|
|
||||||
loader!.style.display = 'none';
|
|
||||||
}, 500);
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -9,18 +9,26 @@ import store from './stores';
|
|||||||
import './styles/index.scss';
|
import './styles/index.scss';
|
||||||
import 'virtual:uno.css';
|
import 'virtual:uno.css';
|
||||||
import 'element-plus/dist/index.css';
|
import 'element-plus/dist/index.css';
|
||||||
// SVG插件配置
|
|
||||||
import 'virtual:svg-icons-register';
|
import 'virtual:svg-icons-register';
|
||||||
|
|
||||||
|
// 创建 Vue 应用
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
|
// 安装插件
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(ElMessage);
|
app.use(ElMessage);
|
||||||
app.use(ElementPlusX);
|
app.use(ElementPlusX);
|
||||||
// 注册ElementPlus所有图标
|
|
||||||
|
// 注册图标
|
||||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||||
app.component(key, component);
|
app.component(key, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(store);
|
app.use(store);
|
||||||
|
|
||||||
|
// 挂载 Vue 应用
|
||||||
|
// mount 完成说明应用初始化完毕,此时手动通知 loading 动画结束
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
|
|
||||||
|
// 通知 index.html 的 loading 动画进度拉满并淡出
|
||||||
|
(window as any).finishLoading?.();
|
||||||
|
|||||||
Reference in New Issue
Block a user