electron实现加载页(启动页)

思路

  1. 创建loading页
  2. 创建loading进程
  3. 主进程之前加载loading进程
  4. loading进程隐藏销毁,然后进入主进程

思路+AI=轻松解决

1. 在index.html同级创建一个loading.html

样式是找AI要的,假的进度条,按照大概的加载时间给duration ,最后的加载完成需要从主进程中给消息,然后直接到100%。

html 复制代码
<!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返回主进程窗口

ts 复制代码
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. 创建一个消息通信

ts 复制代码
onLoadingComplete: (callback) => ipcRenderer.once('loading-complete', callback)

4. 在主进程启动之前调用loading进程进入加载页,然后销毁加载页进入主进程

loading进程里面返回主进程

ts 复制代码
  app.whenReady().then(async () => {
    //开发用
    showLoading(createWindow).then((res: BrowserWindow) => {
      mainWindow = res
      /**
       * @description 修改文件后 检查保存文件
       */
      checkSaveFile(mainWindow)
      /**
       * @description 直接关闭窗口
       */
      closeWindow(mainWindow)
    })
  })

先隐藏在销毁,然后展示主进程

ts 复制代码
  mainWindow.on('ready-to-show', () => {
    //隐藏启动页
    if (loadingWindow && !loadingWindow?.isDestroyed()) {
      loadingWindow?.hide()
      loadingWindow?.removeAllListeners()
      loadingWindow?.destroy()
    }
    mainWindow.show()
  })

实现效果

加载页


进入系统

注意打包时候需要把loading.html打包进去

这里我用的electron-vite

ts 复制代码
// 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')
        }
      }
    },
  }
})
相关推荐
江城开朗的豌豆24 分钟前
Vue-router方法大全:让页面跳转随心所欲!
前端·javascript·vue.js
江城开朗的豌豆36 分钟前
Vue路由动态生成秘籍:让你的链接'活'起来!
前端·javascript·vue.js
江城开朗的豌豆42 分钟前
在写vue公用组件的时候,怎么提高可配置性
前端·javascript·vue.js
江城开朗的豌豆42 分钟前
Vue路由跳转的N种姿势,总有一种适合你!
前端·javascript·vue.js
江城开朗的豌豆43 分钟前
Vue路由玩法大揭秘:三种路由模式你Pick谁?
前端·javascript·vue.js
江城开朗的豌豆44 分钟前
Vue路由守卫全攻略:给页面访问装上'安检门'
前端·javascript·vue.js
江城开朗的豌豆1 小时前
Vue路由传参避坑指南:params和query的那些猫腻
前端·javascript·vue.js
十里青山1 小时前
超好用的vue图片预览插件更新啦,hevue-img-preview 7.0.0版本正式发布,支持vue2/vue3/移动/pc,增加缩略图、下载、自定义样式等
前端·javascript·vue.js
daols888 小时前
vue vxe-table 自适应列宽,根据内容自适应宽度的2种使用方式
vue.js·vxe-table
行云&流水10 小时前
Vue3 Lifecycle Hooks
前端·javascript·vue.js