1个窗口3个Webview:ChatGPT桌面客户端的多Webview架构10分钟看懂
【免费下载链接】ChatGPT❄️ ChatGPT Desktop Application (Mac, Windows and Linux)项目地址: https://gitcode.com/GitHub_Trending/cha/ChatGPT
这篇文章带你用10分钟看懂 ChatGPT 桌面客户端(Mac / Windows / Linux)的核心架构:它如何用1 个窗口承载 3 个 Webview,把官方网页、自定义标题栏、底部快捷提问框装进同一个应用里。项目基于 Tauri + React + Rust 构建,是学习「多 Webview 桌面应用架构」的优秀开源样本 🚀
先看效果:一个窗口,三种界面区域
从演示动图可以看出,整个应用虽然看起来像一个普通网页窗口,但内部其实是三层界面叠在一起:
- 顶部 28px:自定义标题栏(地址标识、前进/后退/刷新、置顶、主题切换)
- 中部主体:ChatGPT 官方网页(chatgpt.com)
- 底部 120px(可选开启):独立的快捷提问输入框(Ask Mode)
这三层,就是三个独立的 Webview。
架构总览:core 窗口如何挂载 3 个 Webview
一切的起点在 src-tauri/src/core/setup.rs。应用启动时,Rust 后端做了三件事:
- 创建唯一窗口
core(初始 800×600,最小 300×200),macOS 下使用 Overlay 标题栏样式隐藏系统标题栏; - 构建
mainWebview,加载https://chatgpt.com,并注入初始化脚本; - 构建
titlebar与ask两个 Webview,分别加载index.html?type=titlebar和index.html?type=ask。
然后通过add_child按坐标和尺寸把三者拼进同一个窗口:
| Webview | 加载内容 | 位置 | 职责 |
|---|---|---|---|
main | chatgpt.com | 主体区域 | 真正的聊天网页 |
titlebar | 本地 index.html | 顶部 28px 高 | 自定义导航与工具按钮 |
ask | 本地 index.html | 底部 120px 高 | 快捷提问输入框 |
高度常量定义在 src-tauri/src/core/constant.rs:TITLEBAR_HEIGHT = 28.0、ASK_HEIGHT = 120.0。
为什么要把 Webview 拆成三个?
这是整套架构最值得新手借鉴的地方 💡
- main 是第三方网站:ChatGPT 页面自带侧边栏、用户头像等 UI,无法改造。把网页「原封不动」放进一个 Webview,才能始终跟随官方更新。
- titlebar 必须是自己的:要显示当前 URL、实现刷新/前进/后退、窗口置顶、主题切换等功能,只能在窗口顶部叠一层「自己的」Webview 来完成。
- ask 输入框独立成层:它不占用网页空间,且可以独立获取焦点。用户可以在 Ask 框里快速输入并直接发送,无需和网页内的输入框抢焦点。
前端的两个「本地页面」由路由分发:src/routes.tsx 根据 URL 参数type把请求导向 Titlebar 视图 或 Ask 视图,同一个index.html入口即可渲染出两种界面。
三个 Webview 之间如何「对话」
跨 Webview 协作靠两条通道,全部在 Rust 侧中转 ⚙️
通道一:URL 变更广播。启动时向main注入 INIT_SCRIPT 脚本,劫持history.pushState/popstate等事件。每当网页内部跳转,脚本就通过 Tauri 事件把新 URL 发给titlebar,标题栏随即更新地址胶囊。
通道二:IPC 命令。命令注册在 src-tauri/src/main.rs,实现在 src-tauri/src/core/cmd.rs:
view_reload/view_go_back/view_go_forward:标题栏按钮 → 对main执行location.reload()、history.back()等;window_pin:切换窗口置顶并持久化配置;ask_sync/ask_send:Ask 输入框的关键魔法 👇
Ask 的完整链路非常巧妙(src/view/Ask.tsx):
- 用户在底部框里打字 →
ask_sync命令 → Rust 在main里执行ChatAsk.sync(文本),实时把内容「镜像」到网页内的真实输入框; - 按
Ctrl+Enter(macOS 为⌘+Enter)→ask_send命令 → 执行ChatAsk.submit()提交,500ms 后焦点回到 Ask 框,形成「连续提问」流。
也就是说:你打的是自己的输入框,发送的却是网页里的输入框,用户体验像原生应用,底层却零侵入网页。
细节亮点:布局重排与跨平台差异
- 窗口缩放自适应:
on_window_event监听Resized事件,实时重算三个 Webview 的位置与尺寸(setup.rs 重排逻辑); - macOS 与其他系统布局不同:macOS 的
main下移到 28px 之下以避开红绿灯按钮,其他系统main从 (0,0) 开始、标题栏压在网页底部(setup.rs 平台分支); - Ask 模式开关:
set_view_ask命令在开启/关闭时重排布局并切换焦点,状态写入本地配置(src-tauri/src/core/conf.rs); - 下载拦截:
main的下载请求被重定向到系统下载目录,完成后自动打开文件(setup.rs)。
10分钟复盘:关键文件清单
想动手阅读源码?按这个顺序,10 分钟即可跑通理解:
- src-tauri/src/main.rs — 入口与 IPC 命令注册
- src-tauri/src/core/setup.rs — 窗口 + 3 Webview 构建与布局(核心中的核心)
- src-tauri/src/core/constant.rs — 高度常量与注入脚本
- src-tauri/src/core/cmd.rs — 所有跨视图命令的实现
- src/routes.tsx — 前端如何按
type参数渲染标题栏/输入框 - src-tauri/tauri.conf.json — 应用配置
总结
ChatGPT 桌面客户端用「1 窗口 + 3 Webview」的多 Webview 架构,优雅地解决了「原生体验 vs 第三方网页不可控」的矛盾:让网页做网页擅长的事,让原生层做网页做不了的事。这套思路——主视图 + 功能条视图分层叠放、Rust 中转通信、注入脚本桥接事件——同样适用于任何需要包装 Web 服务的桌面应用开发,非常值得新手借鉴 ✨
【免费下载链接】ChatGPT❄️ ChatGPT Desktop Application (Mac, Windows and Linux)项目地址: https://gitcode.com/GitHub_Trending/cha/ChatGPT
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考