如何访问<webview>(NW.JS / Electron)内部的内容?

时间:2019-01-11 23:49:56

标签: webview nwjs

出于性能原因,我在NW.JS中使用<webview>标签代替了iFrame(出于性能原因),但找不到关于NWJS docs或实际{{3}的详细信息}。

我只是想从document.title中检索<webview>,然后将其发送回主进程。

1 个答案:

答案 0 :(得分:1)

Webview的文档有限(可通过NWJS / Electron访问),因此很难弄清楚如何做一些基本的事情,例如访问Webview内部或从Webview内部进行访问,因此希望对您有所帮助。

FYI-在Electron和NWJS的上下文中,<webview>标签允许您呈现网站(如iframe),其优点是可以在单独的过程中运行。这比一堆iframe的性能要好得多。 <webview>包含一个标准HTML文档,之所以说iframe复杂,是因为它在单独的进程中运行。

在主进程和<webview>内部之间进行通信的基本解决方案是使用Webview的自定义ContentWindow.postMessage()方法。这高度基于window.postMessage()。通过使用postMessage()(特别是跟踪event.source),我们在主进程和<webview>之间建立了沟通桥梁。

它是如何工作的(至少是我找到的一种方法):

  1. 首先,将来自主进程的EventListeners绑定到<webview>和窗口(以稍后监听来自<webview>内部的消息)
  2. <webview>元素加载URL时,它会触发contentload()
  3. contentload()会将EventListener注入<webview>中,并设置我们想从<webview>内部获取的数据/ DOM元素。
  4. <webview>一旦完成加载,就会触发loadstop()
  5. loadstop()将向<webview>发送消息以建立网桥。重要的是要注意,这里我使用webview.contentWindow.postMessage()而不是window.postMessage()
  6. <webview>使用我们在步骤1设置的数据进行响应
  7. 当主进程从<webview>接收回响应(通过EventListener“消息”)时,它将触发receiveHandshake()
  8. 您现在可以在receiveHandshake()内部访问来自<webview>内部的数据。这可以是页面标题,也可以是您在webviewInjectScript中配置的任何内容。
  9. 最后,我打电话给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支持,请参见:here。还有another thread关于在Electron中使用IPC的信息。 NW.JS对我来说不是一个选择。