思路
- 创建loading页
- 创建loading进程
- 主进程之前加载loading进程
- loading进程隐藏销毁,然后进入主进程
思路+AI=轻松解决
1. 在index.html同级创建一个loading.html
样式是找AI要的,假的进度条,按照大概的加载时间给duration
,最后的加载完成需要从主进程中给消息,然后直接到100%。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>xxx软件启动页</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f7fa;
font-family: 'Arial', sans-serif;
}
.loader-container {
width: 600px;
height: 400px;
background-color: white;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 40px;
box-sizing: border-box;
}
.loader-title {
font-size: 24px;
color: #333;
margin-bottom: 30px;
font-weight: 500;
}
.progress-container {
width: 80%;
height: 8px;
background-color: #e0e5ec;
border-radius: 4px;
margin-bottom: 30px;
overflow: hidden;
}
.progress-bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
border-radius: 4px;
transition: width 0.3s ease;
}
.percentage {
font-size: 36px;
font-weight: 300;
color: #4facfe;
margin-bottom: 20px;
}
.loading-text {
font-size: 16px;
color: #888;
text-align: center;
line-height: 1.5;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid rgba(79, 172, 254, 0.2);
border-top: 4px solid #4facfe;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 30px;
display: none;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="loader-container">
<div class="spinner" id="spinner"></div>
<div class="loader-title">正在加载内容...</div>
<div class="percentage" id="percentage">0%</div>
<div class="progress-container">
<div class="progress-bar" id="progressBar"></div>
</div>
<div class="loading-text" id="loadingText">初始化系统资源,请稍候...</div>
</div>
<script>
const progressBar = document.getElementById('progressBar')
const percentage = document.getElementById('percentage')
const loadingText = document.getElementById('loadingText')
const spinner = document.getElementById('spinner')
// 显示旋转动画
spinner.style.display = 'block'
loadingText.textContent = '正在加载...'
// 分阶段加载动画
function animateProgress() {
let progress = 0
const targetProgress = 100
const duration = 8000 // 总动画时长2秒
const startTime = Date.now()
function update() {
const elapsed = Date.now() - startTime
progress = Math.min((elapsed / duration) * 100, targetProgress)
progressBar.style.width = `${progress}%`
percentage.textContent = `${Math.floor(progress)}%`
// 更新加载状态文本
if (progress < 30) {
loadingText.textContent = '初始化系统资源...'
} else if (progress < 70) {
loadingText.textContent = '加载核心模块...'
} else {
loadingText.textContent = '最终处理中...'
}
if (progress < targetProgress) {
requestAnimationFrame(update)
} else {
loadingComplete()
}
}
requestAnimationFrame(update)
}
animateProgress()
function loadingComplete() {
loadingText.textContent = '加载完成!即将进入系统...'
spinner.style.display = 'none'
// 添加完成动画
progressBar.style.transition = 'all 0.5s ease'
progressBar.style.width = '100%'
percentage.textContent = '100%'
}
// 监听主进程消息
window.api.onLoadingComplete(() => {
// 当API完成时,立即完成剩余动画
loadingComplete()
})
</script>
</body>
</html>
2. 创建一个同主进程一样的loading进程
需要preload
往loading.html
传递消息
在这里我需要loading的时候,调通一个接口才能进入主进程,所以用promise返回主进程窗口
function showLoading(cb: () => BrowserWindow): Promise<BrowserWindow> {
return new Promise((resolve) => {
let win: BrowserWindow | null = null
loadingWindow = new BrowserWindow({
show: false,
frame: false, // 无边框(窗口、工具栏等),只包含网页内容
width: 600,
height: 400,
resizable: false,
transparent: false,
icon: join(__dirname, '../../resources/icon.png'), // Windows/Linux
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
/**
* @description 接口调通才创建主进程
*/
loadingWindow.once('show', async () => {
try {
const response = await getHealth()
if (response.data.code === 200) {
// 启动页完成
loadingWindow?.webContents.send('loading-complete')
win = cb()
resolve(win)
}
} catch (error: any) {
loadingWindow?.destroy()
}
})
if (!app.isPackaged && process.env['ELECTRON_RENDERER_URL']) {
loadingWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/loading.html`)
} else {
loadingWindow.loadFile(join(__dirname, '../renderer/loading.html'))
}
loadingWindow.show()
})
}
3. 创建一个消息通信
onLoadingComplete: (callback) => ipcRenderer.once('loading-complete', callback)
4. 在主进程启动之前调用loading进程进入加载页,然后销毁加载页进入主进程
loading进程
里面返回主进程
app.whenReady().then(async () => {
//开发用
showLoading(createWindow).then((res: BrowserWindow) => {
mainWindow = res
/**
* @description 修改文件后 检查保存文件
*/
checkSaveFile(mainWindow)
/**
* @description 直接关闭窗口
*/
closeWindow(mainWindow)
})
})
先隐藏在销毁,然后展示主进程
mainWindow.on('ready-to-show', () => {
//隐藏启动页
if (loadingWindow && !loadingWindow?.isDestroyed()) {
loadingWindow?.hide()
loadingWindow?.removeAllListeners()
loadingWindow?.destroy()
}
mainWindow.show()
})
实现效果
加载页
进入系统
注意打包时候需要把loading.html打包进去
这里我用的electron-vite
// electron.vite.config.ts
export default defineConfig({
main: {
},
preload: {
},
renderer: {
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'src/renderer/index.html'),
loading: resolve(__dirname, 'src/renderer/loading.html')
}
}
},
}
})