preface

The previous article briefly introduced the basic scaffolding of Electron, mainly differentiating the main process from the rendering process, processing environment variables, and making different packages have their own corresponding environment. The next several articles will focus on some processing of the main process. This article will focus on how to create a window.

variable

Here is a brief description of the environment variables injected by VUE-CLI-plugin-electron – Builder and some variables of electron

Process.env.webpack_dev_server_url: NPM run/server_url://localhost:xxxVUE_APP_ENV: our own environment variable, set in.env.xxx last time: process.env.node_env: determine whether we developed locally or packagedconst isMac = process.platform === 'darwin': Check whether the operating system is MAC or another operating systemCopy the code

Create a window

The electron window is usually created using BrowserWindow and then loads the document content by loadURL to the url address or the path of the file:// local HTML file

import { app, protocol } from 'electron'
let win

// register an app protocol for loading documents, which is used for loading packaged documents, similar to the file:// protocol for loading local files
protocol.registerSchemesAsPrivileged([
  { scheme: 'app'.privileges: { secure: true.standard: true}}])// Create a function to create the window. WinConfig is the BrowserWindow configuration, devPath is the develop-time address, and prodPath is the packaged file address
function createWindow(winConfig, devPath, prodPath) {
  const win = new BrowserWindow(winConfig)
  if (process.env.WEBPACK_DEV_SERVER_URL) {
    win.loadURL(process.env.WEBPACK_DEV_SERVER_URL + devPath)
  } else {
    win.loadURL(`app://./${prodPath}`) // The address is in the public folder
  }
  return win
}
// call, which is basically the document loaded at development time is' http://localhost:80 ', and the packaged document loaded is the packaged index.html
win = createWindow({
  height: 810.width: 1440.webPreferences: {}},' '.'index.html')

Copy the code

More pages

Last time we said that we can package multiple pages by setting pages in vue. Config. js. When our project is relatively large, we can try to package multiple pages. Complex pages are preloaded and not displayed, so they are displayed in win.show(), which is a white screen optimization.

Here we are simple, using multi-page packaging to make loader page, first show loader page, and then load our home page.

Renderer loader

SRC /loader creates multiple pages corresponding to main.js and app. vue

Use by the main process

main/config/global.js
global.willQuitApp = false // Will exit
global.tray = null / / tray
global.sharedObject = { // Share objects
  win: ' '
}

export default global


main/config/index.js
const env = process.env
const config = {
  loading: true.winSingle: true.devToolsShow: true.VUE_APP_ENV: env.VUE_APP_ENV,
  NODE_ENV: env.NODE_ENV,
  VUE_APP_VERSION: env.VUE_APP_VERSION
}

if (config.VUE_APP_ENV === 'development') {
  config.devToolsShow = true
} else if (config.VUE_APP_ENV === 'test') {
  config.devToolsShow = true
} else if (config.VUE_APP_ENV === 'production') {
  config.devToolsShow = false
}

module.exports = config
Copy the code

SRC /main/index.js createWindow (createWindow section)

import config from './config/index'
import global from './config/global'
let win = null
let loaderWin = null

function initWindow() {
  if (config.loading) {
    loaderWin = createWindow({
      width: 400.height: 600.frame: false.backgroundColor: '# 222'.show: false.transparent: true.skipTaskbar: true.// Skip the taskbar
      resizable: false.// It can be resized
      webPreferences: {
        experimentalFeatures: true.contextIsolation: false}},'loader'.'loader.html')
    loaderWin.once('ready-to-show'.() = > {
      loaderWin.show()
    })
    loaderWin.on('closed'.() = > {
      loaderWin = null
    })
  }

  win = createWindow({
    height: 810.minHeight: !isMac && process.env.VUE_APP_ENV === 'production' ? 810 - 20 : 810.width: 1440.minWidth: 1440.useContentSize: true.show: false.webPreferences: {
      contextIsolation: false.nodeIntegrationInSubFrames: true.webSecurity: false.webviewTag: true.enableRemoteModule: true.scrollBounce: isMac
    }
  }, ' '.'index.html')
  win.once('ready-to-show'.() = > {
    loaderWin && loaderWin.destroy()
    win.show()
    // setTimeout(() => {
    // loaderWin && loaderWin.destroy()
    // win.show()
    // }, 2000)
  })
  global.sharedObject.win = win
  win.on('closed'.() = > {
    win = null})}async function onAppReady() {
  if(! process.env.WEBPACK_DEV_SERVER_URL) { createProtocol('app')
  }

  initWindow()
}

app.on('ready', onAppReady)

Copy the code

You can refer to the documentation on the official website for most attributes, but only the problematic ones are described here:

  • Ready-to-show is used to ensure that Windows load without a blank screen and flicker. Frame is to set the window with no border. Normally, our software has a bar at the top, zoom in, zoom out and close, and drag function. Setting false can remove the bar (if you want to customize this bar).

  • UseContentSize: Under normal development, our design is usually the height of the document. This does not include the bar above. If it is false, we set the height to the height of the entire software (i.e. the height of the document we are developing). HTML content = height-bar height), if set to true height is the document height we developed.

  • MinHeight: minHeight is actually related to Menu. There is a difference between Win and MAC. In Win, the Menu is located below the horizontal bar, while in MAC, the Menu is located in the upper left corner of the desktop. Generally speaking, Menu is removed in applications of WIN. In order to facilitate debugging, we have separated several environments, and Menu is removed only in production packages. In practice, when Menu is removed, 20 documents need to be subtracted before the height is consistent with the document (I am also confused?). , so there is this processing.

  • Win.show () here, because our volume is too small and the loading is very fast, loaderWin can not see the effect after a flash, so we can add a timer delay here to see the effect.

  • Note that all BrowserWindow instances are assigned with global variables, such as WIN and loaderWin. If these are local variables, the function will be destroyed upon completion, and our window will be destroyed, as will the electron controls such as the tray.

Single window startup software

Created above window completed, but the packaging is completed, click on the icon to start, we will find a problem, we each double-click a startup icon, will start a window (this is common in editor, can try vscode), but in general, should double-click the setup icon, if the software is not running, start the, If our software focuses on our software window at runtime.

In a technical term that guarantees a single instance mechanism, an example of activating the main instance window when the second instance starts, let’s create a new winsingle.js.

import { app } from 'electron'
import global from '.. /config/global'
const gotTheLock = app.requestSingleInstanceLock()

export default function() {
  // Check whether the window exists when clicking the icon to start
  if(! gotTheLock) { app.quit() }else {
    app.on('second-instance'.() = > {
      const win = global.sharedObject.win
      if (win) { 
        if (win.isMinimized()) win.restore()
        if (win.isVisible()) {
          win.focus()
        } else {
          win.show()
        }
      }
    })
  }
}
// use it in the main thread
import winSingle from './services/winSingle'
if (config.winSingle) {
  winSingle()
}
Copy the code

Here by app. RequestSingleInstanceLock () to determine whether a application instance successfully obtained the lock, our program is started for the first time the value is true, at this second instance – event monitoring, . When the second instance is performed and the app is called requestSingleInstanceLock (), the event will be held in your application in the first instance of trigger, so in this event, we can make our window display again. On the second startup, this value is false, which means that the change window exits directly and our first instance’s second-instance event is triggered.

If you use global.sharedobject. win instead of passing our win directly to winSingle, there’s a catch. If you use Win to pass winSingle just by performing a second-instance binding, When second-instance is triggered, Win does not exist, so we cannot get the instance of our window, so we cannot operate the window, so we use global.sharedobject. win, of course, this thing will be used for communication between Windows later.

supplement

Gitee address: gitee.com/ldlw/electr…

Follow the author: wechat search [learn front] public account, that is, you can get the author’s wechat, plus technical exchange group