fix: eliminate white screen on startup
- Main window starts hidden (visible: false), shown after frontend ready - Remove React.StrictMode to reduce initial render overhead - Add loading spinner during app initialization - Use Promise.all + requestIdleCallback to optimize startup timing
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
"minWidth": 960,
|
||||
"minHeight": 640,
|
||||
"resizable": true,
|
||||
"visible": true
|
||||
"visible": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
||||
@@ -1,3 +1,36 @@
|
||||
.app-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #ffffff;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.app-loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 3px solid #e8e8e8;
|
||||
border-top-color: #1a9e8a;
|
||||
border-radius: 50%;
|
||||
animation: app-loading-spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes app-loading-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.app-loading-text {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #1a9e8a;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.app-layout {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
|
||||
+22
-7
@@ -69,16 +69,22 @@ function App() {
|
||||
const [currentPage, setCurrentPage] = useState<PageType>('video-creation');
|
||||
const [showLogoutConfirm, setShowLogoutConfirm] = useState(false);
|
||||
const [appEnvironment, setAppEnvironment] = useState<string>('production');
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
|
||||
// 应用启动时加载配置和认证状态
|
||||
useEffect(() => {
|
||||
loadAppConfig()
|
||||
.then(config => {
|
||||
setApiBaseUrl(config.apiBaseUrl);
|
||||
setAppEnvironment(config.environment);
|
||||
})
|
||||
.catch(console.error);
|
||||
loadFromStorage().catch(console.error);
|
||||
Promise.all([
|
||||
loadAppConfig()
|
||||
.then(config => {
|
||||
setApiBaseUrl(config.apiBaseUrl);
|
||||
setAppEnvironment(config.environment);
|
||||
})
|
||||
.catch(console.error),
|
||||
loadFromStorage().catch(console.error),
|
||||
]).finally(() => {
|
||||
// 确保至少显示 300ms 加载态,避免闪屏
|
||||
setTimeout(() => setIsReady(true), 300);
|
||||
});
|
||||
}, [loadFromStorage]);
|
||||
|
||||
// 固定浅色模式
|
||||
@@ -109,6 +115,15 @@ function App() {
|
||||
setCurrentPage(page as PageType);
|
||||
};
|
||||
|
||||
if (!isReady) {
|
||||
return (
|
||||
<div className="app-loading">
|
||||
<div className="app-loading-spinner" />
|
||||
<div className="app-loading-text">美家卡智影</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Toast 全局挂载 - 不受登录状态影响 */}
|
||||
|
||||
+26
-6
@@ -16,10 +16,30 @@ document.addEventListener('contextmenu', (e) => {
|
||||
}
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
||||
|
||||
root.render(
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
// 前端渲染完成后,通知 Tauri 显示主窗口
|
||||
// 使用 requestIdleCallback 确保首帧已绘制
|
||||
const showWindow = () => {
|
||||
import('@tauri-apps/api/webviewWindow')
|
||||
.then(({ getCurrentWebviewWindow }) => {
|
||||
const win = getCurrentWebviewWindow();
|
||||
win.show();
|
||||
win.setFocus();
|
||||
})
|
||||
.catch(() => {
|
||||
// 非 Tauri 环境(如浏览器开发)忽略
|
||||
});
|
||||
};
|
||||
|
||||
if ('requestIdleCallback' in window) {
|
||||
requestIdleCallback(showWindow, { timeout: 500 });
|
||||
} else {
|
||||
setTimeout(showWindow, 100);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user