多 WebView 管理 (Multiple WebViews)
zero-native 将每个原生窗口建模为一组命名的 WebView 堆栈。WebView 可以通过设置其大小(Frame)和层级(Layer)来填充整个窗口、覆盖特定面板大小的区域,或者位于另一个 WebView 之上。
对于浏览器外壳(Browser Chrome)、仪表板(Dashboards)、预览(Previews)、授权流(Auth Flows)以及任何需要在隔离的页面内容旁显示受信 UI 的应用,这都是一种非常理想的模型。
启动时的应用源是默认被信任的 WebView,命名为 main。简单的应用可以忽略这一点并继续只使用单个页面。高级应用可以调整 main 的尺寸,并在其上方或下方放置隔离的子 WebView。main 是保留名称,无法使用该标签创建子 WebView。
JavaScript API
从允许的源中启用内置的 WebView 辅助函数:
const app_permissions = [_][]const u8{zero_native.security.permission_window};
.security = .{
.permissions = &app_permissions,
.navigation = .{ .allowed_origins = &.{ "zero://app", "https://example.com" } },
},
.js_window_api = true,然后即可在 JavaScript 中创建和管理 WebView:
const preview = await window.zero.webviews.create({
label: "preview",
url: "https://example.com",
frame: { x: 24, y: 24, width: 480, height: 320 },
layer: 10,
transparent: false,
bridge: false,
});
await preview.setFrame({ x: 32, y: 32, width: 640, height: 420 });
await preview.navigate("https://example.com/docs");
await preview.setZoom(1.25);
await preview.setLayer(20);
await preview.close();- 坐标系统:坐标是相对于父窗口的逻辑内容坐标:
x: 0, y: 0表示窗口内容区域的左上角。 - 层级 (Layer):控制原生层面的堆叠顺序。较高的层级会显示在较低层级的上方。DOM 的
z-index仅仅影响同一个 WebView 内部元素的堆叠,它无法将一个 WebView 置于另一个 WebView 之上。 - 透明度 (Transparent):
transparent: true用于为应用外壳和菜单界面请求透明的原生 WebView 背景。该支持取决于具体的后端,且为尽力而为(Best Effort)实现。 - 桥接 (Bridge):
bridge: true会将window.zero注入到该 WebView 中。请仅在受信任的应用外壳(App Chrome)中使用它。对于不受信任的外部网页内容,应保持为false。 - windowId:默认为调用该命令的窗口。如果显式传递,则它必须与调用窗口相匹配;一个窗口无法管理另一个窗口的 WebView。
- webviews.list():返回结果中首个元素为
main,随后是调用窗口中已打开的子 WebView。main会返回当前的启动 WebView 的位置尺寸(Frame)、层级(Layer)、桥接状态以及源 URL。
您也可以使用显式的 builtin_bridge 策略代替 js_window_api 来启用这些辅助函数。在这种模式下,需要列出应用调用的每一个 WebView 命令:zero-native.webview.create, zero-native.webview.list, zero-native.webview.setFrame, zero-native.webview.navigate, zero-native.webview.setZoom, zero-native.webview.setLayer 和 zero-native.webview.close。
生命周期
- 唯一性标签:WebView 的标签(Label)在每个父窗口中必须是唯一的。在同一窗口下创建具有相同标签的第二个 WebView 会失败;如果想替换它,请先关闭已有的 WebView。
- main 的特权:在支持的后端上,可以通过
setFrame({ label: "main", ... })和setZoom({ label: "main", ... })调整mainWebView 的大小并进行缩放。但它无法被关闭或替换。main的层级叠放取决于后端实现;建议使用子 WebView 层级以获得可移植的堆叠表现。 - 从属销毁与安全:当父窗口关闭时,其下属的子 WebView 也会随之关闭。子 WebView 默认不会接收到
window.zero,因此不受信任的内容无法通过应用桥接调用原生的桥接命令。 - 数量上限:WebView 的槽位限制是针对每个运行时全局计算的,而不是针对单个窗口。默认上限为 16 个子 WebView。
底层命令
辅助函数在内部调用了以下内置的桥接命令:
| 辅助函数 | 底层命令 | 描述 |
|---|---|---|
window.zero.webviews.create(options) / preview | zero-native.webview.create | 在父窗口中创建命名的 WebView |
window.zero.webviews.list() | zero-native.webview.list | 列出调用窗口中的所有 WebView |
window.zero.webviews.setFrame(options) / preview.setFrame(frame) | zero-native.webview.setFrame | 移动或缩放 WebView |
window.zero.webviews.navigate(options) / preview.navigate(url) | zero-native.webview.navigate | 将 WebView 导航至新的 URL |
window.zero.webviews.setZoom(options) / preview.setZoom(zoom) | zero-native.webview.setZoom | 设置页面缩放比例(0.25 至 5.0) |
window.zero.webviews.setLayer(options) / preview.setLayer(layer) | zero-native.webview.setLayer | 修改原生堆叠层级顺序 |
window.zero.webviews.close(options) / preview.close() | zero-native.webview.close | 关闭 WebView |
在创建原生视图或进行导航之前,WebView 的 URL 会先根据运行时的导航策略进行检查。请在加载目标源之前将其加入到 security.navigation.allowed_origins 中。
后端支持情况 (Backend Support)
- 系统 WebView 堆栈:在 macOS 和 Linux 上已实现多层级、尽力而为的透明度支持、支持桥接的受信任子 WebView、针对性桥接响应以及页面缩放。Windows WebView2 的子 WebView 功能正在开发中:安装了 WebView2 时即可使用子层级与导航,但启用桥接的子 WebView 和对
mainWebView 的 frame/zoom/layer 操作将显式返回“后端不支持(unsupported-backend)”的错误。 - CEF 堆栈:macOS 下的 CEF 支持多层级子 WebView、页面缩放以及启用桥接的受信任子 WebView。Linux 下的 CEF 会显式拒绝创建子 WebView,直至原生 CEF 嵌入功能开发完毕。