Основные технологии
- HTML, CSS, JavaScript
- Chromium - отображение контента.
- Node.js - для работы с файловой системой и операционной системой
- Свое API - для работы с часто используемымы функциями операционной системы.
Настройка среды
- Установить nodejs.
- Установить npm.
- Выбрать редактор кода. Рекомендации: Atom, Visual Studio Code.
- Почти все поддерживают javascript.
Создание приложения
- Инициализировать приложение.
- Установить пакет electron.
- В секцию scripts, ключ start, прописать "electron ." для запуска приложения
- Использовать openDevTools
mkdir my-electron-app && cd my-electron-app
npm init -y
npm i --save-dev electron
Структура файлов
my-electron-app/
├── package.json
├── main.js
└── index.html
- package.json - конфигурационный файл проекта.
- main.js - логика приложения на JavaScript.
- index.html - интерфейс приложения.
main.js
const { app, BrowserWindow } = require('electron')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
win.loadFile('index.html')
win.webContents.openDevTools()
}
app.whenReady().then(createWindow)
Класс BrowserWindow
- Создает и управляет окном.
- Свойства (например, backgroundColor).
- События (например, ready-to-show).
- Функции (например, getAllWindows()).
Пример события для BrowserWindow
const { BrowserWindow } = require('electron')
let win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
win.show()
})
Модальное окно
const { BrowserWindow } = require('electron')
let top = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
let child = new BrowserWindow({ parent: top, modal: true, show: false })
child.loadURL('https://github.com')
child.once('ready-to-show', () => {
child.show()
})
Процессы
- Основной (main) процесс (всегда один).
- Процесс отрисовки (на каждое окно свой).
Основной процесс
- Создает веб страницы как экземпляры BrowserWindow.
- Веб страница работает в своем собственном процессе отрисовки.
- Когда удаляется экземпляр BrowserWindow, то соответствующий процесс отрисовки убивается.
- Управляет всеми веб страницами и их процессами отрисовки.
Процесс отрисовки
- Управляет соответствующей страницей.
- Проблема в одном из процессов отрисовки (например, аварийный остонов) не влияет на другие.
- Взаимодействуют между собой через IPC.
ipcMain
- Асинхронное взаимодействие из главного процесса с процессами отрисовки.
// In main process.
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})
ipcRenderer
- Асинхронное взаимодействие из процесса рисования с главным процессом.
// In renderer process (web page).
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
Полный пример.
<html>
<head>
<meta charset = "UTF-8">
<title>File read using system dialogs
</head>
<body>
<script type = "text/javascript">
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
</script>
</body>
</html>
HTML
- Теги: иерархическая структура (открытый, закрытый тек, пустой тег).
- Начальный тег: html
- Теги: head, body.
- Содержимое head: meta, link, scripts.
- Примеры тегов: h1, h2, h3, h4, ul, li и др.
- Тег ссылки: a
- Построение таблиц: table, thead, tbody, tfoot, tr, td.
- Списки: ul, li.
- Формы: input.
CSS
- Таблица стилей
- Подключение: inline, в документе (тег style) и файлом (тег link).
Пример
#tags_form_space ul.tagit {
border-radius: 0;
border: none;
background: black;
color: white;
font-size: 18px;
padding-left: 12px;
}
Селекторы
- * - все элементы (универсальный).
- .class - выбранный класс (свойство class).
- #id - идентификатор (свойство id).
- input - по элементу.
- a[href^=https] - по атрибуту.
Комбинаторы
- , (запятая) - перечисление (И).
- ' ' (пробел) - все дочерние.
- > - первый уровень вложенности.
- + - следующий соседний.
- ~ - все соседние в рамках одного родителя
Объект document
- Представляет собой загруженный DOM документ
- Класс Element
- Класс Node
Свойства документа
- lastModified
- location
- cookie
Доступ к элементам (Element)
- getElementById
- getElementsByClassName
- getElementsByName
- getElementsByTagName
Свойства элемента
- innerHtml
- className
- id
- scrollTop
- style
Примеры работы функций доступа к элементам
// Получение элемента по идентификатору и изменение его свойства
var element = document.getElementById(id);
element.style.color = 'red';
// Получение элементов по имени класса.
var allOrangeJuiceByClass = document.getElementsByClassName('orange juice');
var result = "";
for (var i=0, len=allOrangeJuiceByClass.length; i > len; i=i+1) {
result += "\n " + allOrangeJuiceByClass[i].textContent;
}
Открытие диалогового окна
ipcMain.on('openFile', (event, path) => {
const {dialog} = require('electron')
const fs = require('fs')
dialog.showOpenDialog(function (fileNames) {
// fileNames is an array that contains all the selected
if(fileNames === undefined) {
console.log("No file selected");
} else {
readFile(fileNames[0]);
}
});
})
Открытие диалогового окна
function readFile(filepath) {
fs.readFile(filepath, 'utf-8', (err, data) => {
if(err){
alert("An error ocurred reading the file :" + err.message)
return
}
// handle the file content
event.sender.send('fileData', data)
})
}
Открытие диалогового окна
<html>
<head>
<meta charset = "UTF-8">
<title>File read using system dialogs</title>
</head>
<body>
<script type = "text/javascript">
const {ipcRenderer} = require('electron')
ipcRenderer.send('openFile', () => {
console.log("Event sent.");
})
ipcRenderer.on('fileData', (event, data) => {
document.write(data)
})
</script>
</body>
</html>
Производительность
- С осторожностью подключать модули (изучать зависимости и ресурсы, которые на это требуются).
- Откладывать загрузку модулей на столько позже, насколько это возможно.
- Все работы с I/O выносить из главного процесса (если блокируется главный процесс, то блокируется все приложение).
Производительность
- Исключить polyfill. Всегда знаете какой движок используется. Если код переносится с web проекта, то лучше убедиться, что отсутствуют подключения различных polyfill реализаций.
- Избегать лишних запросов к сети. Лучше включить ресурс в приложение, чем подгрузить его с сети.
- Объединять код в один файл с помощью специальных средств (webpack, parcel, rollup.js и др.).
Производительность. require
const fs = require('fs')
const fooParser = require('foo-parser')
class Parser {
constructor () {
this.files = fs.readdirSync('.')
}
getParsedFiles () {
return fooParser.parse(this.files)
}
}
const parser = new Parser()
module.exports = { parser }
Производительность. require
const fs = require('fs')
class Parser {
async getFiles () {
this.files = this.files || await fs.readdir('.')
return this.files
}
async getParsedFiles () {
const fooParser = require('foo-parser')
const files = await this.getFiles()
return fooParser.parse(files)
}
}
const parser = new Parser()
module.exports = { parser }