electron实现加载页(启动页)

发布于:2025-06-14 ⋅ 阅读:(21) ⋅ 点赞:(0)

思路

  1. 创建loading页
  2. 创建loading进程
  3. 主进程之前加载loading进程
  4. 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进程

需要preloadloading.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')
        }
      }
    },
  }
})