Ограниченная документация по Webview (доступная через NWJS / Electron) делает очень трудным понимание того, как делать основные вещи, такие как получение доступа к / изнутри Webview, так что, надеюсь, это поможет.
FYI - в контексте Electron и NWJS тег <webview>
позволяет отображать веб-сайты (например, iframe), с тем преимуществом, что он выполняется в отдельном процессе. Это намного лучше для производительности, чем куча фреймов. <webview>
содержит стандартный HTML-документ, сложность которого, скажем, в iframe заключается в том, что он выполняется в отдельном процессе.
Основным решением для связи между основным процессом и внутри <webview>
является использование пользовательского метода ContentWindow.postMessage()
Webview. Это в значительной степени основано на window.postMessage()
. Используя postMessage()
- в частности, отслеживание event.source
- мы создаем коммуникационный мост между основным процессом и <webview>
.
Как это работает (хотя бы один способ, который я нашел):
- Во-первых, свяжите EventListeners из основного процесса с
<webview>
и окном (чтобы позже прослушать сообщение, приходящее из <webview>
)
- Когда элемент
<webview>
загружает URL, он вызывает contentload()
contentload()
вставит EventListener в <webview>
и настроит элементы data / DOM, которые мы хотим получить из <webview>
.
- Как только
<webview>
заканчивает загрузку, запускается loadstop()
loadstop()
отправит сообщение на <webview>
, чтобы установить мост. Важно отметить, что здесь я использую webview.contentWindow.postMessage()
вместо window.postMessage()
.
-
<webview>
отвечает данными, которые мы настроили на шаге 1
- Когда главный процесс получает ответ (через EventListener «message») от
<webview>
, он запускает receiveHandshake()
- Внутри
receiveHandshake()
теперь у вас есть доступ к данным, поступившим из <webview>
. Это может быть заголовок страницы или что-то еще, что вы настроили в webviewInjectScript
.
- Наконец, я звоню
removeListeners()
, чтобы удалить все настроенные нами EventListener, но вы можете продолжать отправлять сообщения туда и обратно.
const webview = document.getElementById('your-webview-element');
// <webview> Content is loaded
function contentload() {
// The following will be injected in the webview
const webviewInjectScript = `
var data = {
title: document.title,
url: window.location.href
};
function respond(event) {
event.source.postMessage(data, '*');
}
window.addEventListener("message", respond, false);
`;
webview.executeScript({
code: webviewInjectScript
});
}
// <webview> Loading has finished
function loadstop() {
webview.contentWindow.postMessage("Send me your data!", "*"); // Send a request to the webview
}
// Bind events
webview.addEventListener("contentload", contentload);
webview.addEventListener("loadstop", loadstop);
window.addEventListener("message", receiveHandshake, false); // Listen for response
function receiveHandshake(event) {
// Data is accessible as event.data.*
// This is the custom object that was injected during contentload()
// i.e. event.data.title, event.data.url
console.log(event.data)
// Unbind EventListeners
removeListeners();
}
// Remove all event listeners
function removeListeners() {
webview.removeEventListener("loadstart", loadstart);
webview.removeEventListener("contentload", contentload);
webview.removeEventListener("loadstop", loadstop);
window.removeEventListener("message", receiveHandshake);
}
(Примечание: протестировано только в NW.JS). Информацию о поддержке Electron в Webview смотрите: здесь . Также есть другой поток об использовании IPC в Electron. Это не вариант для меня с NW.JS.