La estructura de los menús no es más que un array de objetos con una estructura predefinida; podemos definir las opciones en el menú de dos tipos, personalizadas y con roles predefinidos como presentaremos en los siguientes apartados.
Un menú clásico luce de la siguiente manera:
const { Menu } = require('electron')
const template = [
***
{
label: 'About us',
submenu: [
***
{
label: "About the app",
click() {
//console.log("Hello world")
// TO DO
}
},
]
},
]
Cada menú está acompañado de un submenú en el cual indicamos los ítems del menú, que pueden ser personalizados o de roles predefinidos que veremos más adelante; en definitiva y como puedes ver en la estructura anterior, un menú está compuesto de un array, por lo tanto, podemos colocar tantos ítems en nuestro menú como necesitemos; a su vez, la propiedad de submenus es un array asi que, puedes indicar tantos items como desees.
Volviendo a la clasificación o opciones, tenemos dos:
Opciones personalizadas
La idea principal de los menús es que, podamos incluir opciones personalizadas para poder usar a lo largo de la aplicación; por ende, se usan como un evento de tipo click en JavaScript asociado a un botón (por ejemplo) pero, en este caso, en vez de un botón, es una opción en un menú:
const { Menu, shell } = require('electron')
const template = [
{
role: 'About Electron',
submenu: [
{
label: "About the app",
click() {
shell.openExternal("https://www.electronjs.org")
}
},
]
},
]
Con el shell, podemos abrir una página web en un enlace, como si se tratase de un enlace de navegación.
Su uso es muy sencillo, y son las que empleamos cuando queremos usar algún método personalizado.
Roles predefinidos
Con los roles ya contamos con funciones específicas que podemos reutilizar fácilmente:
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ role: 'togglefullscreen' }
Los cuales permiten:
- reload, Recargar la página.
- forceReload, Forzar la recarga de la página (vienen siendo un host reloading).
- toggleDevTools, Activar la consola de desarrolladores del navegador.
- resetZoom, Restablecer el zoom.
- zoomIn, Zoom In, aumentar el zoom.
- zoomOut, Zoom Out, Reducir el zoom.
- togglefullscreen, Habilita el modo full screen de la aplicación.
También tenemos el separador para organizar los menús:
{
type:'separator'
},
Finalmente, un menú luce como el siguiente:
Como puedes ver, al ser una estructura grande, lo mejor es definirlo en un archivo aparte:
menu.js
const { app, ipcMain, Menu, shell, BrowserWindow, globalShortcut } = require('electron')
const { open_file, save_file } = require("./editor-options")
const template = [
{
label: 'About us',
click() {
shell.openExternal("https://www.electronjs.org")
}
},
{
label: 'File',
submenu: [
{
label: "Save",
accelerator: 'CommandOrControl+Shift+S',
click() {
const win = BrowserWindow.getFocusedWindow()
win.webContents.send('editorchannel', 'file-save')
}
},
{
label: "Open",
accelerator: 'CommandOrControl+Shift+O',
click() {
const win = BrowserWindow.getFocusedWindow()
open_file(win)
}
},
]
},
{
label: 'Style and format',
submenu: [
{
label: 'Bold',
click() {
const win = BrowserWindow.getFocusedWindow()
win.webContents.send('editorchannel', 'style-bold')
console.log("Negritas")
}
},
{
label: 'Italic',
click() {
const win = BrowserWindow.getFocusedWindow()
win.webContents.send('editor-channel', 'style-italic')
}
},
{
type: 'separator'
},
{
label: 'H1',
click() {
const win = BrowserWindow.getFocusedWindow()
win.webContents.send('editor-channel', 'style-h1')
}
},
{
label: 'H2',
click() {
const win = BrowserWindow.getFocusedWindow()
win.webContents.send('editor-channel', 'style-h2')
}
},
]
}
]
if (process.platform == 'win32' || process.platform == 'darwin') {
template.push(
{
label: 'Default',
submenu: [
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{
type: 'separator'
},
{ role: 'togglefullscreen' },
]
}
)
}
ipcMain.on('editor-channel', (event, arg) => {
console.log("Mensaje recibido del canal 'editor-channel': " + arg)
})
ipcMain.on('file-open', (event, arg) => {
const win = BrowserWindow.getFocusedWindow()
open_file(win)
})
ipcMain.on('file-save', (event, arg) => {
const win = BrowserWindow.getFocusedWindow()
save_file(win, arg)
})
app.on('ready', () => {
globalShortcut.register('CommandOrControl+Shift+S', () => {
const win = BrowserWindow.getFocusedWindow()
win.webContents.send('editor-channel', 'file-save')
})
globalShortcut.register('CommandOrControl+Shift+O', () => {
const win = BrowserWindow.getFocusedWindow()
open_file(win)
})
});
const menu = Menu.buildFromTemplate(template);
module.exports = menu
Para consumirlo, tenemos, desde el archivo principal:
const menu = require('./menu')
***
app.whenReady().then(createWindow)
Menu.setApplicationMenu(menu)
Y al ejecutar un:
npm run start
Tenemos:
Este contenido forma parte tanto de mi libro en Electron como de mi curso de Electron.
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter