Electron : création et gestion de fenêtres

Dans Electron, les fenêtres (Window) sont le moyen central d'interaction entre l'application et l'utilisateur.

Toutes les interfaces visibles s'exécutent surRenderer Processet la création et le contrôle de ces fenêtres sont gérés par leMain Processresponsable.


Création et gestion de fenêtres

Electron à l'aide deBrowserWindowla classe pour créer des fenêtres.

Dans le processus principal, une nouvelle fenêtre est définie de la manière suivante :

Exemple

const { BrowserWindow } = require('electron')

let mainWindow = new BrowserWindow({
  width: 1200,
  height: 800,
  show: false, // Attendre que la page soit prête avant de l'afficher
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
  },
})

Options de configuration de BrowserWindow

  • width / height: Largeur et hauteur de la fenêtre.
  • minWidth / minHeight: Limite de taille minimale.
  • resizable: Indique si le redimensionnement est autorisé.
  • fullscreen / fullscreenable: Indique s'il faut passer en plein écran.
  • frame: Indique s'il faut afficher la barre de titre native (souvent désactivée lors de l'utilisation d'une barre de titre personnalisée).
  • transparent: Fenêtre transparente (peut permettre d'obtenir des effets tels que le verre dépoli, le flottement, etc.).
  • alwaysOnTop: Indique si la fenêtre est toujours au premier plan.

Taille, position et état de la fenêtre
L'état de la fenêtre peut être contrôlé via l'API :

mainWindow.maximize()   // 最大化
mainWindow.minimize()   // 最小化
mainWindow.restore()    // 还原
mainWindow.setBounds({ x: 100, y: 100, width: 800, height: 600 }) // 调整位置和大小

Vous pouvez également écouter les changements de la fenêtre :

mainWindow.on('resize', () => console.log('窗口尺寸变化'))
mainWindow.on('move', () => console.log('窗口移动'))

Fenêtres sans cadre et barre de titre personnalisée
Paramètresframe: falseEnsuite, vous pouvez personnaliser la zone de la barre de titre et simuler le glissement à l'aide de CSS et JS :

.titlebar {
  -webkit-app-region: drag;
}

Notez que les zones non glissables (telles que les boutons) doivent être ajoutées avec :

.titlebar {
  -webkit-app-region: drag;
}

Écoute des événements de fenêtre

mainWindow.on('close', (e) => {
  e.preventDefault()
  mainWindow.hide()
})

Les événements courants incluent :

  • ready-to-show: La page a terminé son chargement et peut être affichée en toute sécurité.
  • focus / blur: La fenêtre obtient ou perd le focus.
  • closed: La fenêtre a été détruite.

Chargement du contenu de la page

Les fenêtres Electron peuvent charger des fichiers HTML locaux ou des sites web distants.

Charger des fichiers HTML locaux

mainWindow.loadFile('index.html')

Charger une URL distante

mainWindow.loadURL('https://example.com')

Utilisation de frameworks frontend
Si vous utilisez des frameworks modernes tels que Vue, React ou Angular, vous pouvez charger les fichiers statiques générés dans la fenêtre :

mainWindow.loadFile(path.join(__dirname, 'dist/index.html'))

Ou chargez un service local en mode développement :

mainWindow.loadURL('http://localhost:5173')

Communication entre fenêtres

Dans les applications multi-fenêtres, vous pouvez avoir besoin de transmettre des données entre fenêtres ou de contrôler le comportement.

Relation parent-enfant entre fenêtres
Peut être spécifié lors de la création d’une nouvelle fenêtreparent:

let child = new BrowserWindow({
  parent: mainWindow,
  modal: true, // 模态窗口
  width: 400,
  height: 300,
})

Lorsque la fenêtre parent est fermée, les fenêtres enfant se ferment également automatiquement.

Partage de données multi-fenêtres
Vous pouvez utiliser le processus principal comme intermédiaire pour transmettre des données entre différents processus de rendu, ou utiliser des objets globaux ouipcMain / ipcRenderer。

Passage de messages entre fenêtres
Le processus principal peut agir directement sur la fenêtre cible :

child.webContents.send('update-data', someData)

Recevoir dans la fenêtre enfant :

const { ipcRenderer } = require('electron')
ipcRenderer.on('update-data', (event, data) => {
  console.log(data)
})

Optimisation de l'interface

Écran de démarrage
Lorsque la fenêtre principale se charge lentement, vous pouvez d'abord afficher une fenêtre de démarrage légère :

const splash = new BrowserWindow({ width: 400, height: 300, frame: false })
splash.loadFile('splash.html')

mainWindow.once('ready-to-show', () => {
  splash.close()
  mainWindow.show()
})

Optimisation de l'affichage de la fenêtre
Les techniques courantes pour éviter le scintillement de l'écran blanc incluent :

  • Utilisationshow: falseCréer une fenêtre, et une fois le chargement terminé,show()。
  • Définir la couleur d'arrière-plan sur la page rendue.
  • Précharger les ressources (icônes, polices, styles).

Techniques pour éviter le scintillement

  • Activer l'accélération GPU ou désactiver l'accélération matérielle (selon la situation).
  • Éviter les animations complexes ou les dégradés en CSS.
  • Utiliser un rendu à double tampon pour réduire la gigue de dessin.

Application Electron multi-fenêtres (comprenant une page de démarrage, l'interface principale et les fenêtres enfants)

Structure des répertoires

my-electron-app/
├── package.json
├── main.js             # 主进程入口
├── preload.js          # 预加载脚本
├── splash.html         # 启动画面
├── index.html          # 主窗口页面
├── child.html          # 子窗口页面
└── renderer.js         # 渲染进程逻辑

main.js (processus principal)

Exemple

const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')

let mainWindow, splash, childWindow

function createSplash() {
  splash = new BrowserWindow({
    width: 400,
    height: 300,
    frame: false,
    transparent: true,
    alwaysOnTop: true,
  })
  splash.loadFile('splash.html')
}

function createMainWindow() {
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    show: false,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  })

  mainWindow.loadFile('index.html')

  // Afficher après le chargement complet de la page
  mainWindow.once('ready-to-show', () => {
    if (splash) splash.close()
    mainWindow.show()
  })

  mainWindow.on('closed', () => (mainWindow = null))
}

function createChildWindow() {
  childWindow = new BrowserWindow({
    parent: mainWindow,
    modal: true,
    width: 400,
    height: 300,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  })
  childWindow.loadFile('child.html')
}

// Communication inter-processus
ipcMain.on('open-child', () => {
  if (!childWindow) createChildWindow()
})

ipcMain.handle('get-app-info', () => {
  return {
    name: app.getName(),
    version: app.getVersion(),
  }
})

app.on('ready', () => {
  createSplash()
  setTimeout(() => createMainWindow(), 1500)
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit()
})

preload.js(script de préchargement)
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
  openChild: () => ipcRenderer.send('open-child'),
  getAppInfo: () => ipcRenderer.invoke('get-app-info'),
})

index.html (fenêtre principale)

Exemple

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>fenêtre principale</title>
  <style>
    body { font-family: sans-serif; text-align: center; margin-top: 100px; }
    button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
  </style>
</head>
<body>
  <h1>Bienvenue dans les applications Electron</h1>
  <p id="info"></p>
  <button id="open">Ouvrir une sous-fenêtre</button>

  <script src="renderer.js"></script>
</body>
</html>

child.html (fenêtre enfant)

Exemple

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>fenêtre enfant</title>
  <style>
    body { font-family: sans-serif; text-align: center; margin-top: 100px; }
  </style>
</head>
<body>
  <h2>Ceci est une fenêtre enfant</h2>
  <p>Peut recevoir des commandes de la fenêtre principale</p>
</body>
</html>

splash.html (Écran de démarrage)

Exemple

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>Chargement...</title>
  <style>
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background: linear-gradient(135deg, #8EC5FC, #E0C3FC);
      font-family: sans-serif;
    }
    h1 {
      font-size: 28px;
      color: #333;
    }
  </style>
</head>
<body>
  <h1>L'application démarre, veuillez patienter...</h1>
</body>
</html>

renderer.js (logique de rendu)

Exemple

const info = document.getElementById('info')
const btn = document.getElementById('open')

// Afficher les informations de l'application
window.electronAPI.getAppInfo().then((appInfo) => {
  info.textContent =`Nom de l'application :${appInfo.name}| Version : ${appInfo.version}`
})

// Ouvrir la fenêtre enfant
btn.addEventListener('click', () => {
  window.electronAPI.openChild()
})

Le processus après exécution est le suivant :

  1. Afficher au démarrageÉcran de démarrage(splash.html)。
  2. Une fois le chargement terminé, fermer automatiquement la page de démarrage et afficherla fenêtre principale。
  3. La fenêtre principale peut être ouverte via un boutonfenêtre enfant, démontrant la fonctionnalité de communication IPC.
  4. La fenêtre principale utilisePreload qui expose de manière sécurisée des API, empêchant l'accès direct à Node.js.
  5. Toutes les fenêtres utilisentl'écoute d'événements、l'affichage différéet d'autres stratégies d'optimisation pour éviter les écrans blancs et le scintillement.
autres extensions