TypePHP\Qt
指南
控件
深入
参考
FAQ
  • English
  • 简体中文
GitHub
指南
控件
深入
参考
FAQ
  • English
  • 简体中文
GitHub
  • 控件目录

    • 控件目录
    • 容器
    • 输入控件
    • 数据控件
    • 展示控件
    • WebView(内嵌网页)

WebView(内嵌网页)

WidgetTree::webView() 在窗口里嵌入一个网页视图。有三种后端,编译期三选一 —— PHP 代码三个后端完全一样,能力不对等的地方见下表。

后端用在JS远程 http(s)://data:本地文件zoom
WebView2Windows,且启用了 SDK✅✅✅✅✅
WKWebViewmacOS(默认启用)✅✅✅✅✅
QTextBrowserLinux,以及关掉上面两个开关时❌❌❌✅❌ 静默忽略

QTextBrowser 是 Qt 自带的 HTML 子集渲染器,没有任何网络栈:给它 https://… 只会得到一片空白, 而且不报错。需要远程页面或 JS 的应用应该用 webViewSupportsJs() 做降级,而不是指望它。

查当前用的是哪个:

$app->webViewBackend();      // 'webview2' | 'wkwebview' | 'textbrowser'
$app->webViewSupportsJs();   // bool

用它做优雅降级,而不是留一片空白:

$app->view(function () use ($state, $app): array {
    return WidgetTree::vbox([
        $app->webViewSupportsJs()
            ? WidgetTree::webView($state->url, ['id' => 'wv', 'grow' => 1])
            : WidgetTree::label('这个页面需要 JavaScript,当前后端跑不了。',
                                ['id' => 'fallback']),
    ]);
});

两种喂数据的方式

// 1. URL —— 远程地址,或按「可执行文件目录」解析的本地文件
WidgetTree::webView('https://example.com', ['id' => 'wv']);
WidgetTree::webView('assets/help.html', ['id' => 'wv']);   // 本地文件

// 2. 直接给 HTML 字符串
WidgetTree::html('<h1>你好</h1><p>直接渲染。</p>', ['id' => 'wv']);
属性说明
url要加载的地址。带 scheme 的(http://、https://、file://、data:)原样交给后端 —— 但只有 WebView2 / WKWebView 认这些 scheme,QTextBrowser 只认 file:;无 scheme 时当本地路径,按可执行文件目录解析(其次工作目录),三个后端都支持
html直接渲染的 HTML 字符串。两者都给时以它为准
zoom缩放因子(WebView2 / WKWebView 支持;QTextBrowser 没有缩放概念,静默忽略)

事件

事件时机valuepayload
loaded导航完成最终 URLsuccess(bool)
title文档标题变化标题—
navigating导航开始目标 URL—
link新窗口请求(target="_blank")URL—

link 不会自己打开任何东西 —— 它只上报,跳不跳由你决定。这和 link 控件是同一套 状态驱动约定:

$app->on('wv', 'link', function (array $event) use ($app) {
    $app->setStatus(['已拦截弹窗:' . $event['value']]);
});

导航动作

三个命令式动作,用来搭浏览器式的工具栏。它们不是属性 —— 没有「正在重载」这种状态可写 —— 所以是一次性调用:

$app->webViewReload('wv');      // 重新加载当前页
$app->webViewGoBack('wv');      // 后退(没有历史时无操作)
$app->webViewGoForward('wv');   // 前进(没有历史时无操作)

它们走的是和表格 appendRows / clear 相同的 call 通道,立即生效,不必等下一帧重渲染。

后端reload / goBack / goForward
WebView2✅
WKWebView(macOS)✅
QTextBrowser❌ 静默忽略 —— 它没有导航栈

「无操作」是刻意的,与「未知属性不报错」同一约定:调用前不需要先判断 webViewBackend()。

启用 WebView2

Windows 上 qtphp new 生成的项目默认就开着。开关是 project.yml 里两行:

link-paths:
  - ../../third_party/webview2/x64      # 包里 vendor 的 SDK
link-libs:
  - WebView2Loader.dll.lib
cxx-flags:
  - /DQT_WEBVIEW2
  - /I"../../third_party/webview2/include"

把 /DQT_WEBVIEW2 注释掉就退化成 QTextBrowser —— 程序照样编译运行,只是没有 JS。

qtphp build 会自动把 195KB 的 WebView2Loader.dll 部署到 exe 旁边。 运行时不在产物里:WebView2 程序需要目标机器装有 WebView2 Runtime, Windows 10/11 随 Edge 自带。缺失时控件会显示一段说明文字,而不是一片空白。

启用 WKWebView(macOS)

macOS 上 qtphp new 生成的 project.macos.yml 默认就开着,开关是 cxx-flags 里两行:

cxx-flags:
  - -DQT_WEBVIEW_WK     # 用系统 WebKit
  - -fobjc-arc          # .mm 里 WKWebView* 是 C++ 类的成员,需要 ARC
ld-flags:
  - -Wl,-framework,WebKit
  - -Wl,-framework,Foundation
  - -Wl,-framework,AppKit

把 -DQT_WEBVIEW_WK 注释掉就退化成 QTextBrowser —— 程序照样编译运行,只是没有 JS。

这条路不需要装任何东西:WebKit 是系统框架,产物体积不变。 刻意没走 Homebrew 的 qtwebview 模块 —— 它在 macOS 上用的本来也是系统 WebView (官方文档:「On macOS, the system web view is used in the same manner as iOS」), 而 brew 的打包会把它和 QtWebEngine(GB 级)绑在一起。

代价是 cpp-src/qt_webview_wk.mm 得进 mac 的 sources。tpc 的配置合并对列表是整体替换, 所以 mac 入口必须把整份 sources 重写一遍再加这一行 —— 也正因如此,Windows / Linux 入口 不列它就绝不会被拿去编 ObjC++。

注意事项

--shot 截不到原生后端的画面

WebView2 画在自己的子窗口里、WKWebView 挂在 Qt 控件的原生 NSView 上,两者都在 Qt 的绘制体系之外, 所以 QWidget::grab()(--shot 用的就是它)不包含那块区域,PNG 里是一片空白。这是后端的限制,不是 bug。

QTextBrowser 后端由 Qt 绘制,所以能截到。

要验原生后端真的把页面加载并执行了,用事件而不是像素:让页面里的脚本改 document.title, 应用收 title 事件 —— 只有 JS 真的跑了才会有那个标题(loaded 同理)。 --selftest 与 --difftest 不受影响:它们只分发事件,不看像素。

给它高度

网页视图对 Qt 的布局尺寸计算毫无贡献(原生后端的像素在 Qt 控件树之外)。控件自带一个合理的 默认尺寸与最小高度;但如果看到它被压成一条细缝,就在能伸展的容器里给它 'grow' => 1, 并确认窗口本身对其余内容来说够高。

QTextBrowser 上跑不了 JavaScript

所有客户端渲染的东西 —— SPA、大多数现代网站 —— 会是空白。用 webViewSupportsJs() 判断并给出 自己的降级提示。静态 HTML、文档页、简单报表在三个后端上都正常。

相关

  • 控件目录 —— 其他控件
  • 属性 —— 通用属性(grow、size 等)
  • 打包 —— 二进制旁边要带哪些东西
在 GitHub 上编辑此页
最后更新: 2026/10/6 03:13
Prev
展示控件