Может ли кто-нибудь помочь мне здесь. Я полностью запутался в том, как решить эту проблему. Я потратил около недели, пытаясь найти решение для этого, но потерпел неудачу, и, похоже, в Интернете отсутствует надежное решение. Я сделал репозиторий github, пытаясь продемонстрировать проблему.
Короче говоря, я реализовал строку состояния в своем приложении, которую я хочу заполнить различными строковыми сообщениями. Эти сообщения будут отправляться из функций, содержащихся в js-файле, который импортирует электрон, что означает, что он не имеет прямого доступа к рендереру. Итак, как я могу отправить эти сообщения в Renderer. Я предполагаю, что это нужно сделать с помощью ContextBridge, но я понятия не имею, как это сделать успешно, поэтому, если ваш ответ просто связывает меня с документами контекстного моста, не беспокойтесь, лол, я утомил себя поиском при этом. Другой альтернативой, которую я рассматривал, является использование пользовательского события, но я не уверен, что это тоже решит проблему.
Вот пример того, что я пытаюсь сделать вместе с репозиторием на github. Если вы сделаете запрос на внесение изменений, чтобы исправить репозиторий, я с удовольствием объединим его и оставлю репозиторий общедоступным, чтобы другие могли извлечь из него пользу и поделиться им с сообществом. https://github.com/JokerMartini/statusbar
В качестве небольшой проблемы я не уверен, почему я больше не могу вызывать getPath из «приложения» из файла js, который не загружен в поток рендеринга.
Я запускаю метод из Renderer
index.vue
const doWork = () => {
window.messenger.doWork();
}
электронная предварительная загрузка.js
import { contextBridge } from "electron";
const messenger = require("../src/helpers/messenger");
contextBridge.exposeInMainWorld("messenger", messenger);
мессенджер.js
const { app } = require("electron");
const path = require("path");
// using electron module to demonstrate this file can't be imported into renderer
export function showMessage(msg) {
const dir = path.join(app.getPath("documents"), "presets");
console.info(dir);
// TODO: send message to renderer...
}
export function doWork() {
console.info("Doing working...");
// step 1: long process
showMessage("Processing step 1...");
// step 2: long process
showMessage("Processing step 2...");
// step 3: long process
showMessage("Processing step 3...");
}
Я хотел бы, чтобы сообщения, отправленные с основного средства визуализации, отображались в строке состояния
main.vue
<q-footer>
<q-bar>
<span class = "text-caption">Show message here...</span>
</q-bar>
</q-footer>
** ОБНОВЛЕНИЕ 01 **
По какой-то причине мое сообщение не принимается в Renderer. Вот мои изменения кода
электронная предварительная загрузка.js
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld("electronAPI", {
setStatus: (callback, func) =>
ipcRenderer.on("set-status", (event, ...args) => func(...args)),
});
index.vue
<template>
<q-page class = "flex flex-center">
<q-btn label = "Show Message" @click = "doWork" />
</q-page>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
setup() {
// send message for testing...
const doWork = () => {
window.electronAPI.setStatus("sfsfsdfsd");
};
// recieve status messages...
window.electronAPI.setStatus("set-status", (data) => {
console.info("STATUS:", data);
// TODO $store.dispatch("....");
});
return {
doWork,
};
},
});
</script>
Вы хотите использовать ipcMain
(в основном процессе) и ipcRenderer
(в процессе рендеринга). Если вы сравните свои скрипты с примерами на https://www.electronjs.org/docs/latest/tutorial/ipc, это то, чего не хватает.
(Есть раздел, посвященный основному рендереру.)
Раньше это было яснее и проще, но давало больше возможностей для злоупотреблений. Поэтому лучше всего игнорировать любые онлайн-уроки старше года или около того. (Хотя contextBridge
довольно новый, поэтому, если они упоминают об этом, они должны быть последними.)
В моем случае работает метод нет для использования скрипта preload.js
для определения конкретных реализаций. Вместо этого я использую скрипт preload.js
, чтобы определить только канал (имена), с которым я могу общаться между основным потоком и потоком рендеринга. IE: Разделяю ваши опасения. Реализуйте свои конкретные функции в сценариях основных потоков и сценариях потоков рендеринга.
preload.js
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [],
// From main to render.
'receive': [
'message:update' // Here is your channel name
],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
Note: Though I do not use Vue.js, you should get the gist of the below two files.
main.js
(основная тема)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const nodePath = require("path");
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
// Send a message to the window.
window.webContents.send('message:update', 'Doing work...');
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
index.html
(рендерить нить)
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>Title</title>
</head>
<body>
<span id = "text-caption">Show message here...</span>
</body>
<script>
// Listen for message updates from the main thread.
window.ipcRender.receive('message:update', (message) => {
document.getElementById('text-caption').innerText = message;
});
</script>
</html>
Это отличная разбивка @midnight-coding Мне было любопытно узнать, как я могу отправлять сообщения из других файлов js, которые могут работать на main, поскольку веб-контент недоступен? Я позвоню ipcRenderer.send("message:update", "hello world")
@JokerMartini Переместите создание вашего окна в отдельный файл. В этом файле добавьте функцию get()
, чтобы вернуть объект окна. ИИ: function get() { return window; }
. Затем в любом файле, который в этом нуждается, require
файл и вызов get()
. НАГ: appMainWindow.get().webContents.send('message:update', 'hello world');
. См. этот ответ для более подробного объяснения.
Можно ли использовать метод ipcRenderer.send? Или это для чего-то другого?
@JokerMartini Извините, я неправильно понял ваш вопрос. Вроде... В скрипте preload.js
команда ipcRenderer.send(...)
настроена под ключ ipcRender.send
, поэтому в файлах скрипта .js
потока рендеринга вы можете вызывать window.ipcRender.send('channel:name', 'This is my data to send to the main thread');
. Используя этот preload.js
-скрипт, не нужно будет пытаться напрямую использовать (в той или иной форме) ipcRenderer.send(...)
, поскольку он реализован через preload.js
-скрипт. Это отвечает на ваш вопрос комментария?
Спасибо, Даррен, ваше предложение немного помогло. Я чувствую, что я очень близко. Я обновил свой ответ выше, если вы вообще можете мне помочь, поскольку вы, кажется, лучше понимаете.