介绍
前一阵子写了一个Demo:electron-multi-tabs,也写了一篇文章:如何实现多tabs的模式。但其实自己对Electron的应用开发,了解也是很少。 最近看了一遍Electron 官网,发现,我Demo中使用的BrowserView 也是官网描述Deprecated的。 通过文章来了解下,几种实现多tabs的方式。
多tabs实现的方式
- WebContentsView :(官方推介:
WebContentsView
s are not a part of the DOM---instead, they are created, controlled, positioned, and sized by your Main process. UsingWebContentsView
, you can combine and layer many pages together in the sameBaseWindow
.) - BrowserView (electron-multi-tabs使用的):(官方提示:The
BrowserView
class is deprecated, and replaced by the newWebContentsView
class.) - Iframes :Iframe 在 Electron 中的行为与普通浏览器中类似。 在宿主页面的 Content Security Policy 允许范围内,一个
<iframe>
元素能在页面上显示外部网页。 要限制<iframe>
标签中站点的功能数量,建议 使用sandbox
属性 并且只允许您想要支持的功能。 - WebView :WebViews are based on Chromium's WebViews and are not explicitly supported by Electron. 我们不能保证WebView API 在未来版本的 Electron 中仍然可用。 这就是为什么如果您想要使用
<webview>
标签,您需要在BrowserWindow
的webPreferences
中设置webviewTag
为true
。(官方提示:我们不建议您使用 WebView,因为这个标签会发生剧烈的结构变化,可能会影响您应用程序的稳定性。 Consider switching to alternatives, likeiframe
and Electron'sWebContentsView
, or an architecture that avoids embedded content by design.)
多Tabs样例源码:electron-multi-tabs,效果图:
WebContentsView 官方样例
js
const { BaseWindow, WebContentsView } = require('electron')
const win = new BaseWindow({ width: 800, height: 400 })
const view1 = new WebContentsView()
win.contentView.addChildView(view1)
view1.webContents.loadURL('https://electronjs.org')
view1.setBounds({ x: 0, y: 0, width: 400, height: 400 })
const view2 = new WebContentsView()
win.contentView.addChildView(view2)
view2.webContents.loadURL('https://github.com/electron/electron')
view2.setBounds({ x: 400, y: 0, width: 400, height: 400 })
简单理解下代码:创建了一个窗口,通过x坐标,把页面一分为二,左边一个页面,右边一个页面。BaseWindow的contentView对象可以添加无数个可视对象。
BrowserView 官方样例
js
// 在主进程中.
const { app, BrowserView, BrowserWindow } = require('electron')
app.whenReady().then(() => {
const win = new BrowserWindow({ width: 800, height: 600 })
const view = new BrowserView()
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadURL('https://electronjs.org')
})
上述的代码,实现的逻辑跟WebContentsView差不多。 原理:通过setBounds,设置width和height为0,则内容不可见;剩下的设置为window的width和height就可以了。
Iframes
这个官方都赖得给样例代码了,因为不推介啊。
js
const { BrowserWindow, webFrameMain } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadFile('你的html')
win.webContents.on(
'did-frame-navigate',
(event, url, httpResponseCode, httpStatusText, isMainFrame, frameProcessId, frameRoutingId) => {
const frame = webFrameMain.fromId(frameProcessId, frameRoutingId)
if (frame) {
console.log(frame.url)
}
}
)
- 从官网上了解,frame.url在主进程中是只读的,所以,变更和设置iframe的url地址,需要通过preload.js这个桥梁文件进行。
- 上述的设计思路:一个iframe,不停的切换url,显示不同的tab的相关内容,这样的好处是,内存永远是一个页面的大小。坏处是加载很慢,而且没有keepalive。如果要一个tab一个iframe,也是可行的,但是,为了内存考虑,还是需要做限制,如上限是10个tab。
总之,不推介。
WebView
警告
Electron的 webview
标签基于 Chromium webview
,后者正在经历巨大的架构变化。 这将影响 webview
的稳定性,包括呈现、导航和事件路由。 We currently recommend to not use the webview
tag and to consider alternatives, like iframe
, a WebContentsView
, or an architecture that avoids embedded content altogether.
启用
默认情况下,Electron >= 5禁用 webview
标签。 在构造 BrowserWindow
时,需要通过设置 webviewTag
webPreferences选项来启用标签。 For more information see the BrowserWindow constructor docs.
html
<webview id="foo" src="https://www.github.com/" style="display:inline-flex; width:640px; height:480px"></webview>
js
<script>
onload = () => {
const webview = document.querySelector('webview')
const indicator = document.querySelector('.indicator')
const loadstart = () => {
indicator.innerText = 'loading...'
}
const loadstop = () => {
indicator.innerText = ''
}
webview.addEventListener('did-start-loading', loadstart)
webview.addEventListener('did-stop-loading', loadstop)
}
</script>
使用 webview
标签将'guest'内容 (例如网页) 嵌入到您的 Electron 应用中。 Guest 内容包含在 webview
容器内。 应用中的嵌入页面可以控制外来内容的布局和重绘。
与 iframe
不同, webview
独立于您的应用程序运行。 它拥有和你的页面不一样的权限并且所嵌入的内容和你应用之间的交互都将是异步的。 这将保证你的应用对于嵌入的内容的安全性。 ** 注意: **从宿主页上调用 webview 的方法大多数都需要对主进程进行同步调用。总之,不推介。
总结
我也是一个Electron开 发的新人,所以每走一步都会记录下来相关的一些心得。在这里跟大家一起共勉。