使用五种方式确保加载指示器被正确隐藏: - Flutter 第一帧渲染完成事件 - Flutter 引擎初始化检查 - 10秒超时保护 - 页面加载后检查 Flutter 视图 - 定期轮询检查 Flutter 视图 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
186 lines
5.4 KiB
HTML
186 lines
5.4 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<!--
|
||
If you are serving your web app in a path other than the root, change the
|
||
href value below to reflect the base path you are serving from.
|
||
|
||
The path provided below has to start and end with a slash "/" in order for
|
||
it to work correctly.
|
||
|
||
For more details:
|
||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||
|
||
This is a placeholder for base href that will be replaced by the value of
|
||
the `--base-href` argument provided to `flutter build`.
|
||
-->
|
||
<base href="/">
|
||
|
||
<meta charset="UTF-8">
|
||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||
<meta name="description" content="Monisuo - Crypto Trading App">
|
||
|
||
<!-- iOS meta tags & icons -->
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||
<meta name="apple-mobile-web-app-title" content="Monisuo">
|
||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||
|
||
<!-- Favicon -->
|
||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||
|
||
<title>Monisuo</title>
|
||
<link rel="manifest" href="manifest.json">
|
||
|
||
<style>
|
||
/* 加载指示器样式 */
|
||
.loading-container {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
||
z-index: 9999;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 50px;
|
||
height: 50px;
|
||
border: 3px solid rgba(255, 255, 255, 0.1);
|
||
border-top: 3px solid #3498db;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
}
|
||
|
||
.loading-text {
|
||
margin-top: 20px;
|
||
color: #ffffff;
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
font-size: 16px;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
/* 隐藏加载指示器 */
|
||
.loading-hidden {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 0.3s ease-out;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- 加载指示器 -->
|
||
<div id="loading" class="loading-container">
|
||
<div class="loading-spinner"></div>
|
||
<div class="loading-text">Loading...</div>
|
||
</div>
|
||
|
||
<noscript>
|
||
<div style="text-align: center; padding: 50px; font-family: sans-serif;">
|
||
<h1>JavaScript Required</h1>
|
||
<p>Please enable JavaScript to run this application.</p>
|
||
</div>
|
||
</noscript>
|
||
|
||
<!--
|
||
You can customize the "flutter_bootstrap.js" script.
|
||
This is useful to provide a custom configuration to the Flutter loader
|
||
or to give the user feedback during the initialization process.
|
||
|
||
For more details:
|
||
* https://docs.flutter.dev/platform-integration/web/initialization
|
||
-->
|
||
<script src="flutter_bootstrap.js" async></script>
|
||
|
||
<!-- 隐藏加载指示器 -->
|
||
<script>
|
||
// 防止重复隐藏
|
||
var loadingHidden = false;
|
||
|
||
function hideLoading() {
|
||
if (loadingHidden) return;
|
||
loadingHidden = true;
|
||
|
||
var loading = document.getElementById('loading');
|
||
if (loading) {
|
||
loading.style.opacity = '0';
|
||
loading.style.transition = 'opacity 0.3s ease-out';
|
||
setTimeout(function() {
|
||
if (loading && loading.parentNode) {
|
||
loading.parentNode.removeChild(loading);
|
||
}
|
||
}, 300);
|
||
}
|
||
}
|
||
|
||
// 方式1: Flutter 第一帧渲染完成(最可靠的方式)
|
||
window.addEventListener('flutter-first-frame', hideLoading);
|
||
|
||
// 方式2: 监听 Flutter 引擎初始化完成
|
||
if (window._flutter) {
|
||
window._flutter.loaderDidLoad = true;
|
||
}
|
||
|
||
// 方式3: 超时保护(10秒后强制隐藏)
|
||
var timeoutId = setTimeout(hideLoading, 10000);
|
||
|
||
// 方式4: 页面完全加载后检查(5秒后)
|
||
window.addEventListener('load', function() {
|
||
setTimeout(function() {
|
||
// 检查 Flutter 应用是否已渲染
|
||
var flutterView = document.querySelector('flutter-view') ||
|
||
document.querySelector('flt-glass-pane');
|
||
if (flutterView) {
|
||
hideLoading();
|
||
} else {
|
||
// 如果还没渲染,再等3秒
|
||
setTimeout(hideLoading, 3000);
|
||
}
|
||
}, 5000);
|
||
});
|
||
|
||
// 方式5: 定期检查 Flutter 视图是否已存在
|
||
var checkInterval = setInterval(function() {
|
||
var flutterView = document.querySelector('flutter-view') ||
|
||
document.querySelector('flt-glass-pane');
|
||
if (flutterView && flutterView.offsetWidth > 0) {
|
||
clearInterval(checkInterval);
|
||
clearTimeout(timeoutId);
|
||
hideLoading();
|
||
}
|
||
}, 500);
|
||
|
||
// 15秒后清除检查间隔
|
||
setTimeout(function() {
|
||
clearInterval(checkInterval);
|
||
}, 15000);
|
||
</script>
|
||
|
||
<!-- vConsole 调试控制台 - 仅在开发环境启用 -->
|
||
<script>
|
||
// 检测是否为开发环境(localhost 或特定端口)
|
||
var isDev = window.location.hostname === 'localhost' ||
|
||
window.location.hostname === '127.0.0.1' ||
|
||
window.location.port !== '' && window.location.port !== '80' && window.location.port !== '443';
|
||
|
||
if (isDev) {
|
||
var script = document.createElement('script');
|
||
script.src = 'https://unpkg.com/vconsole@latest/dist/vconsole.min.js';
|
||
script.onload = function() {
|
||
new VConsole();
|
||
};
|
||
document.body.appendChild(script);
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|