ElectronJS es un marco de código abierto que se utiliza para crear aplicaciones de escritorio nativas multiplataforma utilizando tecnologías web como HTML , CSS y JavaScript que pueden ejecutarse en los sistemas operativos Windows, macOS y Linux. Combina el motor Chromium y NodeJS en un solo tiempo de ejecución.
Cualquier aplicación de escritorio nativa debe integrarse con el entorno del sistema operativo. La aplicación debe tener la capacidad de interactuar con las funciones básicas del sistema operativo, como el sistema de archivos, la bandeja del sistema, etc. Electron nos proporciona un módulo de diálogo incorporado para mostrar los diálogos nativos del sistema para interactuar con los archivos. Este tutorial utilizará el método de instancia del módulo de diálogo para demostrar la funcionalidad de carga de archivos en Electron.
Suponemos que está familiarizado con los requisitos previos que se describen en el enlace mencionado anteriormente. Para que Electron funcione, node y npm deben estar preinstalados en el sistema.
Módulo de Diálogo: El Módulo de Diálogo es parte del Proceso Principal . Para importar y usar el módulo de diálogo en el proceso Renderer , usaremos el módulo remoto Electron .
- Estructura del proyecto:
Ejemplo: Comenzaremos creando la aplicación Electron para la funcionalidad de carga de archivos siguiendo los pasos dados.
- Paso 1: navegue a un directorio vacío para configurar el proyecto y ejecute el siguiente comando,
npm init
Para generar el archivo package.json . Instale Electron usando npm.
npm install electron --save
Esto instalará las dependencias requeridas de node_modules . Instale el paquete axios usando npm.
npm install axios --save
Este paquete es un cliente HTTP basado en Promise para NodeJS. Este paquete se utiliza para realizar llamadas HTTP a las API REST. Para obtener información más detallada sobre axios , consulte este enlace . Cree el archivo sample.txt en la carpeta de activos para fines de demostración.
paquete.json:
{ "name": "electron-fileupload", "version": "1.0.0", "description": "File Upload in Electron", "main": "main.js", "scripts": { "start": "electron ." }, "keywords": [ "electron" ], "author": "Radhesh Khanna", "license": "ISC", "dependencies": { "axios": "^0.19.2", "electron": "^8.2.5" } }
- Paso 2: Este es el archivo main.js. Para obtener el código estándar del archivo main.js , consulte este vínculo . Hemos modificado el código para adaptarlo a las necesidades de nuestro proyecto.
principal.js:
const { app, BrowserWindow } = require(
'electron'
)
function
createWindow() {
// Create the browser window.
const win =
new
BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration:
true
}
})
// Load the index.html of the app.
win.loadFile(
'src/index.html'
)
// Open the DevTools.
win.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
// This method is equivalent to 'app.on('ready', function())'
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on(
'window-all-closed'
,() => {
// On macOS it is common for applications and their menu bar
// To stay active until the user quits explicitly with Cmd + Q
if
(process.platform !==
'darwin'
) {
app.quit()
}
})
app.on(
'activate'
,() => {
// On macOS it's common to re-create a window in the
// app when the dock icon is clicked and there are no
// other windows open.
if
(BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
// In this file, you can include the rest of your
// app's specific main process code. You can also
// put them in separate files and require them here.
- Paso 3: Cree el archivo index.html y el archivo index.js dentro del directorio src . También copiaremos el código repetitivo para el archivo index.html del enlace mencionado anteriormente. Hemos modificado el código para adaptarlo a las necesidades de nuestro proyecto.
índice.html:
<!DOCTYPE html>
<
html
>
<
head
>
<
meta
charset
=
"UTF-8"
>
<
title
>Hello World!</
title
>
/security#csp-meta-tag -->
<
meta
http-equiv
=
"Content-Security-Policy"
content
=
"script-src 'self' 'unsafe-inline';"
/>
</
head
>
<
body
>
<
h1
>Hello World!</
h1
> We are using node
<
script
>
document.write(process.versions.node)
</
script
>, Chrome
<
script
>
document.write(process.versions.chrome)
</
script
>, and Electron
<
script
>
document.write(process.versions.electron)
</
script
>.
<
h3
>File Upload in Electron</
h3
>
<
button
id
=
"upload"
>Upload File</
button
>
<!-- Adding Individual Renderer Process JS File -->
<
script
src
=
"index.js"
></
script
>
</
body
>
</
html
>
- Salida: en este punto, nuestra aplicación está configurada y podemos iniciar la aplicación para verificar la salida de la GUI. Para iniciar la aplicación Electron, ejecute el comando:
npm start
- Paso 4: el botón Cargar archivo aún no tiene ninguna funcionalidad asociada. El dialog.showOpenDialog(browserWindow, options) toma los siguientes parámetros.
- browserWindow: BrowserWindow (Opcional) La instancia de BrowserWindow . Este argumento permite que el cuadro de diálogo se adjunte a la ventana principal, convirtiéndolo en un modal . Una ventana modal es una ventana secundaria que desactiva la ventana principal. Si no se muestra BrowserWindow , el diálogo no se adjuntará. En tal caso, se mostrará como una ventana independiente. En el código anterior, la instancia de BrowserWindow no se pasa al cuadro de diálogo, por lo tanto, el cuadro de diálogo se abre como una ventana independiente al hacer clic en el botón Cargar archivo .
- opciones: Objeto Toma los siguientes parámetros,
- title: String (Opcional) El título que se mostrará en la ventana de diálogo.
- defaultPath: String (Opcional) El directorio que se abrirá según lo definido por la ruta predeterminada al hacer clic en el botón Cargar archivo .
- buttonLabel: String (Opcional) Etiqueta personalizada para el botón de confirmación. Si está vacío, se utilizará la etiqueta predeterminada. En el código anterior se define como Cargar .
- mensaje: string (opcional) Este parámetro solo se admite en macOS . Esto se usa para mostrar el mensaje personalizado encima de los cuadros de entrada.
- securityScopedBookmarks: booleano (opcional) Este parámetro solo se admite en macOS . Este parámetro se usa para crear marcadores con ámbito de seguridad cuando se empaqueta para Mac App Store. Para obtener información más detallada, consulte este enlace .
- filtros: FileFilter[{}] (Opcional) Es una array de objetos. Define una array de tipos de archivos que se pueden mostrar o seleccionar cuando queremos limitar al usuario a un tipo específico. Podemos definir múltiples tipos de archivos pertenecientes a diferentes categorías. El objeto FileFilter toma los siguientes parámetros,
- nombre: String El nombre de la categoría de extensiones.
- extensiones: [] La array de extensiones debe constar de extensiones sin comodines ni puntos, como se muestra en el código. Para mostrar todos los archivos, utilice el comodín * (no se admite ningún otro comodín). Para obtener información más detallada, consulte este enlace .
En el código anterior, queremos restringir al usuario solo a archivos de texto. Por lo tanto, hemos definido el nombre como Archivos de texto y la array de extensiones como [‘txt’, ‘docx’] .
- properties: String[] (Opcional) Contiene una lista de características que están disponibles para el cuadro de diálogo nativo. Toma toma en los siguientes valores,
- openFile: Permite seleccionar los Archivos.
- openDirectory: Permite seleccionar directorios/carpetas.
- multiSelections: permite seleccionar varios archivos en el cuadro de diálogo.
- showHiddenFiles: Mostrar archivos ocultos en el cuadro de diálogo.
- createDirectory: este valor solo se admite en macOS . Permite crear nuevos directorios desde dentro del diálogo. En Windows, el menú contextual está predisponible en el cuadro de diálogo (haga clic con el botón derecho en la ventana de diálogo) y podemos crear nuevos archivos y directorios a partir de él.
- promptToCreate: este valor solo se admite en Windows . Este valor se usa cuando la ruta del archivo ingresada en el cuadro de diálogo no existe en el sistema. En este momento, debería solicitar al usuario que cree. En realidad, esto no crea el archivo en la ruta, pero permite que se devuelvan rutas inexistentes que la aplicación puede crear y usar.
- noResolveAliases: este valor solo se admite en macOS . Deshabilita la resolución automática de la ruta del archivo del alias a su destino original. Los alias seleccionados ahora devolverán la ruta del alias en lugar de la ruta de destino.
- treatPackageAsDirectory: este valor solo se admite en macOS . Trata paquetes como carpetas .app , como un directorio en lugar de un archivo.
- dontAddToRecent: este valor solo se admite en Windows . Este valor significa que el archivo/directorio elegido no debe agregarse a la lista de documentos recientes.
Nota: Según la documentación oficial de Electron, el cuadro de diálogo abierto no puede ser tanto un selector de archivos como un selector de directorios en los sistemas operativos Windows y Linux . Si se especifican ambas propiedades , [‘openFile’, ‘openDirectory’] en estas plataformas, se mostrará el selector de directorio y no podremos seleccionar archivos. Por lo tanto, en el código, hemos especificado diferentes propiedades de diálogo para la plataforma win32/linux y darwin .
El dialog.showOpenDialog(browserWindow, options) devuelve una Promesa . Se resuelve en un Objeto que contiene los siguientes parámetros,
- cancelado: booleano Si se canceló o no la operación de diálogo.
- filePaths: String[] Una array de rutas de archivo elegidas por el usuario. Si se cancela la operación de diálogo, será una array vacía. En caso de que el valor de multiSelections no se proporcione en propiedades , la array filePaths devolverá un solo elemento.
- marcadores: String[] (opcional) Esta array de strings solo es compatible con macOS . Esto se devuelve cuando el parámetro securityScopedBookmarks se especifica como verdadero en el objeto de opciones .
index.js: agregue el siguiente fragmento en ese archivo.
const electron = require(
'electron'
);
const path = require(
'path'
);
// Importing dialog module using remote
const dialog = electron.remote.dialog;
var
uploadFile = document.getElementById(
'upload'
);
// Defining a Global file path Variable to store
// user-selected file
global.filepath = undefined;
uploadFile.addEventListener(
'click'
,() => {
// If the platform is 'win32' or 'Linux'
if
(process.platform !==
'darwin'
) {
// Resolves to a Promise<Object>
dialog.showOpenDialog({
title:
'Select the File to be uploaded'
,
defaultPath: path.join(__dirname,
'../assets/'
),
buttonLabel:
'Upload'
,
// Restricting the user to only Text Files.
filters: [
{
name:
'Text Files'
,
extensions: [
'txt'
,
'docx'
]
}, ],
// Specifying the File Selector Property
properties: [
'openFile'
]
}).then(file => {
// Stating whether dialog operation was
// cancelled or not.
console.log(file.canceled);
if
(!file.canceled) {
// Updating the GLOBAL filepath variable
// to user-selected file.
global.filepath = file.filePaths[0].toString();
console.log(global.filepath);
}
}).
catch
(err => {
console.log(err)
});
}
else
{
// If the platform is 'darwin' (macOS)
dialog.showOpenDialog({
title:
'Select the File to be uploaded'
,
defaultPath: path.join(__dirname,
'../assets/'
),
buttonLabel:
'Upload'
,
filters: [
{
name:
'Text Files'
,
extensions: [
'txt'
,
'docx'
]
}, ],
// Specifying the File Selector and Directory
// Selector Property In macOS
properties: [
'openFile'
,
'openDirectory'
]
}).then(file => {
console.log(file.canceled);
if
(!file.canceled) {
global.filepath = file.filePaths[0].toString();
console.log(global.filepath);
}
}).
catch
(err => {
console.log(err)
});
}
});
Producción:
- Paso 5: Una vez que hayamos obtenido la ruta del archivo desde la ventana de diálogo, podemos seguir cualquiera de los dos enfoques:
- Enfoque 1: cargue el archivo en un servidor haciendo una llamada a la API de REST POST HTTP y deje que el servidor maneje el procesamiento del archivo. Usaremos el paquete axios que se instaló anteriormente para lograr esto.
En el archivo index.js , agregue el siguiente código justo después de console.log(global.filepath); } dentro de Promise
index.js:const fs = require(
'fs'
);
const axios = require(
'axios'
);
if
(global.filepath && !file.canceled) {
var
formData =
new
FormData();
formData.append(
'file'
, fs.createReadStream(global.filepath));
axios.post(
'[Custom URL]'
, formData, {
headers: {
'Content-Type'
:
'multipart/form-data'
}
});
}
// ...
Explicación: Agregamos el archivo a un
formData
objeto usando el módulo fsContent-Type
y configuramos el encabezadomultipart/form-data
para la solicitud POST. Reemplace[Custom URL]
con una URL de la API REST para recibir el archivo en el lado del servidor. Una vez que hemos recibido el archivo en el lado del servidor, podemos dejar que el servidor maneje el procesamiento del archivo y muestre la respuesta respectiva. - Enfoque 2: Procese el archivo en el propio sistema leyendo/manipulando el contenido del archivo. Podemos usar el módulo fs para leer el contenido del archivo y luego realizar más manipulaciones según sea necesario.
En el archivo index.js , agregue el siguiente código justo después de console.log(global.filepath); } dentro de la Promesaconst fs = require(
'fs'
);
const fs = require(
'fs'
);
if
(global.filepath && !file.canceled) {
fs.readFile(global.filepath, {encoding:
'utf-8'
},
function
(err,data) {
if
(!err) {
console.log(
'received data: '
+ data);
}
else
{
console.log(err);
}
});
}
//...
Explicación: Leeremos el archivo de la variable de ruta de archivo GLOBAL que se actualizó desde la ventana de diálogo con
UTF-8
codificación estándar. Una vez que hayamos obtenido con éxito el contenido del archivo, podemos actualizar/manipular el contenido según la funcionalidad deseada.muestra.txt:
Producción:
- Enfoque 1: cargue el archivo en un servidor haciendo una llamada a la API de REST POST HTTP y deje que el servidor maneje el procesamiento del archivo. Usaremos el paquete axios que se instaló anteriormente para lograr esto.
Publicación traducida automáticamente
Artículo escrito por radheshkhanna y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA