предисловие
Некоторое время назад я использовалelectron-vueРазработано кросс-платформенное (в настоящее время поддерживающее Mac и Windows) бесплатное приложение для загрузки изображений с открытым исходным кодом——PicGo, я наступил на много ям в процессе разработки, причем не только со стороны бизнес-логики самого приложения, но и со стороны самого электрона. В процессе разработки этого приложения я многому научился. Поскольку я также начал изучать электрон с нуля, такой большой опыт также должен вдохновить и дать инструкции начинающим ученикам, которые хотят изучать разработку электронов. Поэтому я написал практический опыт разработки Электрона и объяснил его с точки зрения наиболее близкой к разработке реальных инженерных проектов. Надеюсь помочь всем.
Ожидается, что он будет расширен за счет нескольких серий статей или аспектов:
- Начало работы с электрон-вью
- Простая разработка основного процесса и процесса визуализации
- Представляем базу данных json на основе Lodash - lowdb
- Некоторые меры кроссплатформенной совместимости
- Выпуск и обновление через CI
- ... (подумайте о написании снова)
иллюстрировать
PicGo
состоит в том, чтобы принятьelectron-vue
разработан, поэтому, если выvue
, то учиться вместе будет быстрее. Если ваш технический стек похож наreact
,angular
, то чисто по этому туториалу, хотя вы можете и не много узнать о построении стороны рендера (которую можно понимать как страницу), вы все же должны получить соответствующие знания по основной стороне (основной процесс электрон).
Если вы не читали предыдущую статью, вы можете сначала прочитать ее из предыдущей статьи.
Базовое понимание основного процесса и процесса визуализации
Из конца предыдущей статьи мы успешно запустили электронно-вьюDEMOДавайте взглянем на поверхностное понимание этих двух процессов:
Вы можете видеть, что основной процесс управляет этим окном приложения (BrowserWindow), а процесс Renderer отвечает за отрисовку пользовательского интерфейса страницы, с которой мы знакомы. Но на самом деле их гораздо больше. На следующем рисунке можно примерно перечислить электронные или собственные модули, которые они поддерживают и которыми они управляют:
Большинство модулей, перечисленных на рисунке, — это то, что мы будем использовать в процессе разработки.
У них есть свои собственные модули, а также общие модули, такие какclipboard
Ждать. Другая часть — это модуль в процессе Main, но доступ к нему можно получить черезremote
Модуль, который позволяет процессу визуализации также использовать его. НапримерMenu
Напримерshell
Ждать.
Узнайте, какие модули находятся в каких процессах и какие модули доступны черезremote
Это необходимо для того, чтобы модуль использовался процессом рендерера, чтобы мы могли корректно использовать его в последующей разработке.
Некоторые из вышеперечисленных модулей, возможно, не смогут увидеть, что это за функция из названия, это не имеет значения, последующий контент будет освещаться медленно.
Разработка основного процесса
Как упоминалось выше, значительная роль процесса Main заключается в создании окна приложения. Давайте посмотрим, как это достигается.
import { app, BrowserWindow } from 'electron' // 从electron引入app和BrowserWindow
let mainWindow
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080` // 开发模式的话走webpack-dev-server的url
: `file://${__dirname}/index.html`
function createWindow () { // 创建窗口
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000
}) // 创建一个窗口
mainWindow.loadURL(winURL) // 加载窗口的URL -> 来自renderer进程的页面
mainWindow.on('closed', () => {
mainWindow = null
})
}
app.on('ready', createWindow) // app准备好的时候创建窗口
На данный момент, независимо от того, как выглядит страница в процессе рендеринга, открытие окна, когда приложение готово, требует только вызова метода создания.BrowserWindow
можно использовать метод.
Разработка в основном процессе немного написана тогдаjQuery
Внешний вид, более событийное письмо.
app
Обратите внимание, что первыйappМодуль. Этот модуль представляет собой скелетный электрон приложения. Он отвечает за хук всего жизненного цикла приложения, хук и многие другие события.
Общие крючки жизненного цикла приложения следующие:
-
will-finish-launching
Запускается после того, как приложение завершило базовый процесс запуска. -
ready
Запускается, когда электрон закончил инициализацию -
window-all-closed
Срабатывает при закрытии всех окон, в windows и linux при выходе из всех оконкак правилокогда приложение выходит -
before-quit
Уволен перед выходом из приложения -
will-quit
Запускается, когда приложение собирается выйти -
quit
Запускается при выходе из приложения
и мы обычноready
Выполнение операций инициализации, таких как создание окна приложения, создание меню приложения и создание сочетания клавиш приложения. пока вwill-quit
илиquit
При выполнении некоторых операций очистки, таких как отвязка горячих клавиш приложения.
В частности, в АфрикеmacOS
В системе, как правило, когда закрываются все окна приложения, это также время выхода приложения. Так что можно сопоставитьwindow-all-closed
Этот крючок для достижения:
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') { // 当操作系统不是darwin(macOS)的话
app.quit() // 退出应用
}
})
В дополнение к хукам жизненного цикла, упомянутым выше, есть несколько часто используемых хуков событий:
-
active
(только для macOS), когда приложение активно -
browser-window-created
при создании BrowserWindow -
browser-window-focus
Когда браузервинден
Эти крючки должны соответствовать ряду конкретных сценариев для выполнения определенных операций. При таком изменении BrowserWindow активное значение заголовка окна.
Конечно, в дополнение к некоторым из вышеперечисленных обработчиков событий модуль приложения также имеет несколько очень распространенных методов:
-
app.quit()
выйти из приложения -
app.getPath(name)
Используется для получения некоторых системных каталогов, полезен для хранения файлов конфигурации приложений и т. д. -
app.focus()
Используется для активации приложений, различной логики активации системыРазные
Как известны эти события и методы? конечноофициальная документация. Тем не менее, нет необходимости сначала читать официальную документацию по API. Официальная документация по API больше используется для консультаций, когда вы хотите разработать функцию, вы можете проверить, есть ли у нее соответствующий API и как его использовать.
BrowserWindow
Модуль BrowserWindow используется для создания наиболее распространенных окон приложений. Для разных систем стили создаваемых окон по умолчанию также отличаются. Давайте посмотрим на разницу во внешнем виде окон между macOS и Windows:
версия для Mac
версия для Windows
Видно, что область действия (свернуть, развернуть, закрыть) и положение заголовка и меню в верхней части окна существенно различаются. Они такие же, как родные окна системы. Но если вы хотите украсить его, это нормально. Например:
PicGo для Mac
и PicGo для окон
Среди них версия для Mac использует операционную область системы, в то время как Windows не использует операционную область системы, а имитирует ее с помощью значков. Но там же не используется система по умолчаниюtitlebar
. Это будет объединено позжеrenderer
обработать.
Давайте взглянем на общую конфигурацию для создания BrowserWindow:
let window
function createWindow () {
window = new BrowserWindow({
height: 900, // 高
width: 400, // 宽
show: false, // 创建后是否显示
frame: false, // 是否创建frameless窗口
fullscreenable: false, // 是否允许全屏
center: true, // 是否出现在屏幕居中的位置
backgroundColor: '#fff' // 背景色,用于transparent和frameless窗口
titleBarStyle: 'xxx' // 标题栏的样式,有hidden、hiddenInset、customButtonsOnHover等
resizable: false, // 是否允许拉伸大小
transparent: true, // 是否是透明窗口(仅macOS)
vibrancy: 'ultra-dark', // 窗口模糊的样式(仅macOS)
webPreferences: {
backgroundThrottling: false // 当页面被置于非激活窗口的时候是否停止动画和计时器
}
// ... 以及其他可选配置
})
window.loadURL(url)
window.on('closed', () => { window = null })
}
Излишне говорить, что длина и ширина окна должны быть указаны. Некоторые из наиболее важных из них, на которые следует обратить внимание:frame
Эта опция по умолчаниюtrue
. если выбраноfalse
frameless
const createSettingWindow = () => {
const options = {
height: 450,
width: 800,
show: false,
frame: true,
center: true,
fullscreenable: false,
resizable: false,
title: 'PicGo',
vibrancy: 'ultra-dark',
transparent: true,
titleBarStyle: 'hidden',
webPreferences: {
backgroundThrottling: false
}
}
if (process.platform === 'win32') { // 针对windows平台做出不同的配置
options.show = true // 创建即展示
options.frame = false // 创建一个frameless窗口
options.backgroundColor = '#3f3c37' // 背景色
}
settingWindow = new BrowserWindow(options)
settingWindow.loadURL(settingWinURL)
settingWindow.on('closed', () => {
settingWindow = null
})
}
app
BrowserWindow
Есть также много часто используемых обработчиков событий:
-
closed
когда окно закрыто -
focus
когда окно активировано -
show
когда отображается окно -
hide
когда окно скрыто -
maxmize
когда окно развернуто -
minimize
когда окно свернуто ...
Конечно, практических методов еще много:
-
BrowserWindow.getFocusedWindow()
[статический метод] Получить активное окно -
win.close()
[Метод экземпляра, то же самое ниже] Закройте окно -
win.focus()
активировать окно -
win.show()
окно дисплея -
win.hide()
скрыть окно -
win.maximize()
развернуть окно -
win.minimize()
свернуть окно -
win.restore()
Восстановить из свернутого окна ...
Вам нужно выполнять разные операции в окне для разной бизнес-логики. Это должно соответствовать потребностям вашего проекта. Например, как упоминалось выше, рабочая область (увеличение, уменьшение, кнопка закрытия) в верхней части окна может быть реализована с помощью метода имитации значка + экземпляра.
Tray
Сначала вы можете не знать, что это такое. Это можно понять, чтобы понять компоненты значков на панели задач разных систем.
Например, в macOSTray
После сопоставления значка это значок приложения в верхней панели:
Например, в окнахTray
После сопоставления значка это значок приложения в правом нижнем углу Windows:
Следует отметить, что в Windows и macOS размер значка одинаков16*16
Писать Икона верхней колонны под MacOS обычно ходит.黑白
Маршрут, поэтому вы можете подготовить разные значки для обеих систем.PicGo
внутриTray
Сгенерированный код примерно такой:
function createTray () {
const menubarPic = process.platform === 'darwin' ? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png`
tray = new Tray(menubarPic) // 指定图片的路径
// ... 其他代码
}
Обратите внимание, что в приведенном выше коде есть${__static}
Переменные. Переменнаяelectron-vue
Для нашего открытого корневого каталога проектаstatic
Путь к папке. По этому пути каталог, в котором находятся ваши статические ресурсы, может быть хорошо расположен на этапах разработки и производства. очень удобная переменная.
КонечноTray
Не просто икона и ничего больше. Трей поддерживает множество полезных событий. Двумя наиболее важными из них являютсяclick
а такжеright-click
. Соответствует событиям щелчка левой и правой кнопки мыши соответственно.
событие щелчка левой кнопкой мыши
- В системе macOS щелчок левой кнопкой мыши по значку в трее может вызвать меню конфигурации или окно приложения.
- В Windows, щелчок левой кнопкой мыши на значке обычно появится окно приложения для лотка.
Клич правой кнопкой мыши
- В macOS щелчок правой кнопкой мыши по значку в области уведомлений обычно вызывает меню конфигурации.
- Под системой windows, то же, что и выше.
Поэтому нам необходимо адаптироваться к привычкам работы пользователей в разных операционных системах.
В соответствии с PicGo, щелчок левой кнопкой мыши в системе macOS откроет небольшое окно строки меню, а щелчок правой кнопкой мыши откроет меню конфигурации. В Windows главное окно появится сразу при щелчке левой кнопкой мыши (поскольку в Windows нет необходимости в маленьких окнах), а меню конфигурации появится при щелчке правой кнопкой мыши. В PicGo они реализованы следующим образом:
function createTray () {
const menubarPic = process.platform === 'darwin' ? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png`
tray = new Tray(menubarPic)
const contextMenu = // ...菜单
tray.on('right-click', () => { // 右键点击
window.hide() // 隐藏小窗口
tray.popUpContextMenu(contextMenu) // 打开菜单
})
tray.on('click', () => { // 左键点击
if (process.platform === 'darwin') { // 如果是macOS
toggleWindow() // 打开或关闭小窗口
} else { // 如果是windows
window.hide() // 隐藏小窗口
if (settingWindow === null) { // 如果主窗口不存在就创建一个
createSettingWindow()
settingWindow.show()
} else { // 如果主窗口在,就显示并激活
settingWindow.show()
settingWindow.focus()
}
}
})
}
Для macOS в трее также есть отличная функция — вы можете перетаскивать файлы на значок в трее, что вызовет следующие события:
-
drop
когда что-то перетаскивается на иконку -
drop-files
Когда файл перетаскивается на значок -
drop-text
когда текст перетаскивается на иконку -
drop-enter
Когда просто перетащили на иконку -
drop-leave
Когда событие перетаскивания покидает значок -
drop-end
Когда событие перетаскивания заканчивается
Так же, как функция загрузки изображений, реализованная PicGo при перетаскивании изображений на значок в трее, используются некоторые из вышеперечисленных событий:
Обратите особое внимание на то, что значок отличается, когда перетаскивание включено и когда перетаскивание закончилось. Это реализовано в PicGo, очень просто:
tray.on('drag-enter', () => {
tray.setImage(`${__static}/upload.png`)
})
tray.on('drag-end', () => {
tray.setImage(`${__static}/menubar.png`)
})
а такжеTray
Еще одна важная роль — открыть пункт меню. Это будет объединено со следующим разделомMenu
Объясните вместе.
Menu
Мощный компонент «Меню» электрона может не только генерировать пункты системного меню, но и реализовывать функцию привязки общих клавиш быстрого доступа приложений.
Давайте сначала посмотрим, что представляют собой пункты системного меню:
macOS
windows
В основном есть два типа.
- Во-первых, это меню приложения. Для macOS это пункт меню в левой части верхней панели. Для окон это область меню под строкой заголовка окна.
- Второе меню похоже на контекстное меню.
В первое меню можно попасть черезMenu.setApplicationMenu()
реализовать.
Второе меню можно отобразить в два этапа:
1.Создайте меню:
const contextMenu = Menu.buildFromTemplate([...])
2.Показать меню:
tray.on('right-click', () => { // 右键点击tray的时候
tray.popUpContextMenu(contextMenu) // 弹出菜单
})
Здесь мы только вводимMenu
сам. На самом деле составMenu
по одномуMenuItem
. Они бывают многих видов:
- normal
- separator
- submenu
- checkbox
- radio
и много ролей:
- quit
- copy
- redo
- undo
- minimize
- close
- reload
- ...
Вообще говоря, пункты меню конфигурации в основном сгруппированы по типу. Например, пункты меню PicGo:
Есть четыре типа нормальных, подменных, флажков и радио. По умолчанию нормально.
Слова-символы обычно соответствуют некоторому общему поведению. Напримерquit
выйти из приложения, напримерminimize
сводится к минимуму, напримерcopy
является копией. Однако следует отметить, что если вы не укажете сочетания клавиш для этих действий в меню «Создать приложение», то некоторые распространенные сочетания клавиш нельзя будет использовать в вашем приложении. Напримерctrl+c
илиcommand+c
Дублируйте эту операцию, если вы не проходитеMenu.setApplicationMenu()
Если вы установите эту горячую клавишу, то операция копирования не может быть выполнена в вашем электронном приложении. PicGo также делал это в более ранних версиях.ошибка. Проблема в то время заключалась в том, что у меня не было проблем в режиме разработки, но копирование-вставка была невозможна в рабочем режиме. Позже я проверил причину и обнаружил, что в режиме разработки электрон поставит некоторые контекстные меню по умолчанию, как показано на рисунке:
Таким образом, в производственном режиме, если я не добавлю эти сочетания клавиш, пользователь не сможет их использовать.это большая дыра.
Сказав это, давайте посмотрим, как выглядит код, который генерирует меню приложения:
Обратите внимание, что если вы используете только следующие сочетания клавиш непосредственно в режиме разработки, некоторые сочетания клавиш отладки, такие как
F12
илиcommand+shift+i
Операция открытия консоли работать не будет. Поэтому нет необходимости создавать эти контекстные меню в режиме разработки.
const createMenu = () => {
if (process.env.NODE_ENV !== 'development') {
const template = [{
label: 'Edit',
submenu: [
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
{ type: 'separator' },
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' },
{
label: 'Quit',
accelerator: 'CmdOrCtrl+Q',
click () {
app.quit()
}
}
]
}]
menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
}
}
в состоянии пройтиaccelerator
Укажите нужную комбинацию клавиш. Такие какShift
,Ctrl
,Cmd
Эквивалентная аббревиатура ключа. Если это комбинация клавиш, добавьте+
.尤其注意到,因为macOS和windows键位的差异,所以有一个很好用的键位缩写CmdOrCtrl
, т. е. если бы на macOS было быCmd
, на окнах этоCtrl
.
Затем посмотрите на генерацию контекстного меню Tray:
const contextMenu = Menu.buildFromTemplate([
{
label: '关于',
click () {
dialog.showMessageBox({
title: 'PicGo',
message: 'PicGo',
detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`
})
}
},
{
label: '打开详细窗口',
click () {
if (settingWindow === null) {
createSettingWindow()
settingWindow.show()
} else {
settingWindow.show()
settingWindow.focus()
}
}
},
{
label: '选择默认图床',
type: 'submenu',
submenu: [
{
label: '微博图床',
type: 'radio',
checked: db.read().get('picBed.current').value() === 'weibo',
click () {
db.read().set('picBed.current', 'weibo')
.write()
}
},
{
label: '七牛图床',
type: 'radio',
checked: db.read().get('picBed.current').value() === 'qiniu',
click () {
db.read().set('picBed.current', 'qiniu')
.write()
}
},
{
label: '腾讯云COS',
type: 'radio',
checked: db.read().get('picBed.current').value() === 'tcyun',
click () {
db.read().set('picBed.current', 'tcyun')
.write()
}
},
{
label: '又拍云图床',
type: 'radio',
checked: db.read().get('picBed.current').value() === 'upyun',
click () {
db.read().set('picBed.current', 'upyun')
.write()
}
}
]
},
{
label: '打开更新助手',
type: 'checkbox',
checked: db.get('picBed.showUpdateTip').value(),
click () {
const value = db.read().get('picBed.showUpdateTip').value()
db.read().set('picBed.showUpdateTip', !value).write()
}
},
{
role: 'quit',
label: '退出'
}
])
tray.on('right-click', () => {
tray.popUpContextMenu(contextMenu)
})
Обратите внимание, что событие click элемента меню может быть напрямую передано черезclick
свойства указать. Мы прошли первымиMenu.buildFromTemplate()
Этот метод создает меню, а затем щелкает правой кнопкой мышиTray
Когда значок отобразится, поднимите его (PopUp).
Конечно, есть и другие способы построения меню. Доступно через экземпляр менюappend
способ присоединитьсяMenu Item
. Например:
const menu = new Menu()
menu.append(new MenuItem({ label: 'Cut', accelerator: 'CmdOrCtrl+X' }))
menu.append(new MenuItem({ type: 'separator' })) // 分割线
menu.append(new MenuItem({ label: 'Helper', type: 'checkbox', checked: true }))
По сути, с помощью вышеуказанных базовых модулей в основном построен скелет одного из наших приложений с окнами, значками приложений на панели задач и элементами меню. Другие модули основного процесса не нужны и будут постепенно упоминаться в последующих статьях по мере их использования. В следующем разделе мы рассмотрим разработку процесса визуализации.
Разработка процесса визуализации
дляelectron-vue
По большей части процесс рендеринга на самом деле пишет интерфейсные страницы, которые мы обычно пишем. Однако по сравнению со страницами, которые вы обычно пишете в браузере, при написании страниц в электронном виде вы по-прежнему можете использовать множество небраузерных модулей, таких какfs
, такие как электрон черезremote
Модули модули, открытые для процесса рендеринга. Далее, давайте посмотрим, на что должен обращать внимание процесс рендеринга.
Пожалуйста, используйте хеш-режим
Обычно, когда мы пишем Vue, мы предпочитаем открытую маршрутизацию.history
режим, потому что он лучше выглядит в адресной строке браузера - без хэша#
Номер - это просто URL-адрес задней части. Однако следует отметить, чтоhistory
Схема требует поддержки внутреннего сервера.
Возможно, многие друзья не чувствуют этого, когда обычно разрабатывают, потому что vue-cli запускается в режиме разработки.webpack-dev-server
помочь вам реализовать серверhistory-fallback
характеристики. Таким образом, при фактическом развертывании вам, по крайней мере, необходимо использовать программы веб-сервера, такие какnginx
,apache
Настройте соответствующие правила и дайте интерфейсному маршруту вернуться кvue-router
иметь дело с.
И то же самое верно и для электрона. В режиме разработки, посколькуwebpack-dev-server
сервер включен, поэтомуBrowserWindow
Загружается с чего-то вроде ``http://localhost:9080这样的地址的页面。而在生产模式下,却是使用的
file://的协议,比如
file://${__dirname}/index.html`, чтобы указать страницу, загружаемую окном.
Таким образом, вы можете понять из приведенного выше выражения. Предположим, у меня есть подмаршрут с адресомchild
. Если режим хеширования не включен, в режиме разработки проблем нет.http://localhost:9080/child
, но в производственном режиме,file://${__dirname}/index.html/child
Это путь, который не может быть согласован. Итак, под электрономvue-router
пожалуйста, не используйтеhistory
режим и использовать по умолчаниюhash
модель.
Тогда вышеуказанная проблема может быть легко решена, и она станетfile://${__dirname}/index.html#child
Вот и все.
PicGo в правилах маршрутизации загрузки страницы следующие, из которых вы можете видеть, что я используюhash
модель.
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080`
: `file://${__dirname}/index.html`
const settingWinURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/#setting/upload`
: `file://${__dirname}/index.html#setting/upload`
Реализуйте свой собственный заголовок
говорить вышеBrowserWindow
Когда я сказал, что иногда для красоты приложения я не хочу, чтобы наше окно приложения использовало системное значение по умолчанию.titlebar
, и хотите использовать свои собственные написанные для достижения. Это создание вашегоBrowserWindow
Добавьте предложение в конфигурацию
titleBarStyle: 'hidden'
хорошо. Затем вы можете самостоятельно смоделировать верхнюю часть страницы процесса рендеринга.titlebar
, как указано вышеPicGo
изtitlebar
Смотреть. На самом деле код тоже очень простой:
<div class="fake-title-bar">
PicGo - {{ version }}
<div class="handle-bar" v-if="os === 'win32'"> <!-- 如果是windows系统 就加上模拟的操作按钮-->
<i class="el-icon-minus" @click="minimizeWindow"></i>
<i class="el-icon-close" @click="closeWindow"></i>
</div>
</div>
Затем поместите положение этой строки заголовка сверху.
Однако при обычном использовании мы должны обратить внимание на то, что обычно мы можем перетаскивать окно, удерживая мышью строку заголовка. Но если мы не добавим атрибут draggable, в заголовке, который мы написали сами, такой возможности нет. Добавить эту функцию также легко:
.fake-title-bar {
-webkit-app-region drag
}
Сделайте заголовок перетаскиваемым с помощью всего одной строки CSS.
Однако под Windows кнопку (уменьшение, масштабирование и закрытие) долго тащить не стоит, поэтому для нее тоже нужно:
.handle-bar {
-webkit-app-region no-drag
}
сталиno-drag
, который реализует заголовок нашего собственного сгенерированного приложения.
Предотвращение перетаскивания
Обычно, когда мы используем Chrome, есть функция, благодаря которой, если вы перетащите PDF-файл в Chrome, он автоматически откроется с помощью встроенной программы чтения PDF-файлов. Вы перетаскиваете изображение в Chrome, и оно открывается. Благодаря нашему электронному приложениюBrowserWindow
По сути, это также браузер внутри, поэтому эта функция все еще существует. И на это многие не обращают внимания. То есть после того, как вы разработаете электронное приложение, перетащите картинку, pdf и т. д., если это не перетаскиваемая область (например, область загрузки PicGo), то она не должна открывать эту картинку, этот pdf, а исключать Это.
Так что будем слушать глобальноdrag
а такжеdrop
Событие, когда пользователь перетаскивает файл, но не в область перетаскивания, он должен быть заблокирован. Потому что все страницы должны иметь такие функции, поэтому я написал vuemixin
:
export default {
mounted () {
this.disableDragEvent()
},
methods: {
disableDragEvent () {
window.addEventListener('dragenter', this.disableDrag, false)
window.addEventListener('dragover', this.disableDrag)
window.addEventListener('drop', this.disableDrag)
},
disableDrag (e) {
const dropzone = document.getElementById('upload-area') // 这个是可拖拽的上传区
if (dropzone === null || !dropzone.contains(e.target)) {
e.preventDefault()
e.dataTransfer.effectAllowed = 'none'
e.dataTransfer.dropEffect = 'none'
}
}
},
beforeDestroy () {
window.removeEventListener('dragenter', this.disableDrag, false)
window.removeEventListener('dragover', this.disableDrag)
window.removeEventListener('drop', this.disableDrag)
}
}
Таким образом, этот миксин может быть представлен глобально.
Использование удаленного модуля
Удаленный модуль создается электроном, чтобы позволить некоторым модулям, которые изначально работали в процессе Main, выполняться в процессе рендерера. Вот некоторые из них, которые мы будем использовать.
существуетelectron-vue
встроенныйvue-electron
Этот модуль можно легко использовать в vue, напримерthis.$electron.remote.xxx
использовать удаленный модуль.
shell
shell
Официальное описание модуля:Manage files and URLs using their default applications.
То есть приложение по умолчанию, которое использует файл или URL-адрес. Обычно мы можем использовать его, чтобы приложение для работы с изображениями по умолчанию открывало изображение, а браузер по умолчанию открывал URL-адрес.
Если мы хотим нажать кнопку в процессе рендеринга и открыть URL-адрес в браузере по умолчанию, мы можем сделать это:
<button @click="openURL"></button>
<script>
export default {
methods: {
openURL () {
this.$electron.remote.shell.openExternal('https://github.com/Molunerfinn/PicGo')
}
}
}
</script>
Это удобно?
Более подробное использование оболочки может относиться кДокументация.
dialog
Иногда нам нужно открыть родное диалоговое окно. НапримерPicGo
информация о версии:
macOS
windows
В это время можно пройтиdialog
Этот модуль делает это. Та же логика, что и выше, заключается в том, чтобы нажать кнопку, чтобы открыть диалоговое окно:
openDialog () {
this.$electron.remote.dialog.showMessageBox({
title: 'PicGo',
message: 'PicGo',
detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`
})
}
Для получения более подробной информации об использовании диалога см.Документация.
Применение меню и BrowserWindow
использоватьMenu
Многие люди могут быть в состоянии понять. Но зачем использоватьBrowserWindow
Шерстяная ткань? Потому что вам нужно найти вас открытьMenu
окно.
В PicGo есть кнопка, чтобы открыть меню, которое примерно выглядит следующим образом:
buildMenu () {
const template = [...]
this.menu = Menu.buildFromTemplate(template)
},
openDialog () {
this.menu.popup(remote.getCurrentWindow) // 获取当前打开Menu的窗口
}
здесьmenu.popup
Вам нужно указать окно, чтобы открыть это меню. Он автоматически обнаружит, где вы нажали, и появится всплывающее окно.
Связь между основным процессом и процессом рендерера
В Vue, если это не взаимодействие между родительским и дочерним компонентами, оно обычно используется черезBus Event
быть реализованным. Связь между различными процессами в электроне на самом деле очень похожа, черезipcMain
а такжеipcRenderer
быть реализованным. вipcMain
вmain
используется в процессе иipcRenderer
вrenderer
используется в процессе.
ipcMain и ipcRenderer
Пример на официальном сайте на самом деле очень лаконичен и понятен, я его выложил:
// In main process.
const {ipcMain} = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.sender.send('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})
// 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')
вipcMain
мониторить только изipcRenderer
может быть возвращен только после событияipcRenderer
стоимость. а такжеipcRenderer
Можно получить или отправить.
Тогда возникает вопрос, как сделатьipcMain
Как насчет проактивной отправки сообщений? Или пусть основной процесс активно отправляет сообщенияipcRenderer
.
Первое, что нужно уяснить, это то,ipcMain
Невозможно проактивно отправить сообщениеipcRenderer
. Поскольку ipcMain имеет только.on()
метод №.send()
Методы. Так что это можно сделать только другими способами. Есть ли способ? да, использоватьwebContents
.
webContents
webContents
ФактическиBrowserWindow
Атрибут экземпляра. То есть, если нам нужноmain
Чтобы отправить сообщение окну или странице в процессе, вы должны передатьwin.webContents.send()
способ отправки.
Код примерно такой:
// In main process
let win = new BrowserWindow({...})
win.webContents.send('img-files', imgs)
// In renderer process
ipcRenderer.on('img-files', (event, files) => {
console.log(files)
})
Следовательно, окно для отправки должно быть указано, чтобы информация могла быть доставлена точно.
Суммировать
В этой статье подробно описывается электронMain
процесс иRenderer
Базовые знания о процессах имеют отношение к разработке. я много развиваюсьPicGo
Возникшие проблемы и ямы, которые были наступлены. Возможно, за простыми предложениями в тексте - мои бесчисленные чтения и отладки. Содержание намного больше, чем первый, я надеюсь, что эта статья может дать вамelectron-vue
Развитие приносит некоторое вдохновение. Соответствующий код в тексте, вы можете найти его вPicGoНайдено в репозитории проекта, добро пожаловать, нажмите звездочку ~ Надеюсь, эта статья поможет вам, это мое самое счастливое место. Если вам это нравится, добро пожаловать в мой блог и следите за ходом этой серии статей.
Примечание: фотографии в этой статье принадлежат моей личной работе, если не указано иное, если вам нужно перепечатать, пожалуйста, отправьте личное сообщение