Skip to content

多 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 辅助函数:

zig
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:

javascript
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.setLayerzero-native.webview.close

生命周期

  • 唯一性标签:WebView 的标签(Label)在每个父窗口中必须是唯一的。在同一窗口下创建具有相同标签的第二个 WebView 会失败;如果想替换它,请先关闭已有的 WebView。
  • main 的特权:在支持的后端上,可以通过 setFrame({ label: "main", ... })setZoom({ label: "main", ... }) 调整 main WebView 的大小并进行缩放。但它无法被关闭或替换。main 的层级叠放取决于后端实现;建议使用子 WebView 层级以获得可移植的堆叠表现。
  • 从属销毁与安全:当父窗口关闭时,其下属的子 WebView 也会随之关闭。子 WebView 默认不会接收到 window.zero,因此不受信任的内容无法通过应用桥接调用原生的桥接命令。
  • 数量上限:WebView 的槽位限制是针对每个运行时全局计算的,而不是针对单个窗口。默认上限为 16 个子 WebView。

底层命令

辅助函数在内部调用了以下内置的桥接命令:

辅助函数底层命令描述
window.zero.webviews.create(options) / previewzero-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 和对 main WebView 的 frame/zoom/layer 操作将显式返回“后端不支持(unsupported-backend)”的错误。
  • CEF 堆栈:macOS 下的 CEF 支持多层级子 WebView、页面缩放以及启用桥接的受信任子 WebView。Linux 下的 CEF 会显式拒绝创建子 WebView,直至原生 CEF 嵌入功能开发完毕。