Electron `<webview>` 标签完整指南:内嵌外部页面、属性配置与 API 事件全解析
本文基于 Electron 官方仓库中的 docs/api/webview-tag.md 完整整理并辅以源码佐证。
<webview>是 Electron 中用于在应用内隔离地展示外部 Web 内容的标签:它像<iframe>一样嵌入页面,却运行在独立进程与独立 frame 中。读完本文,你将掌握如何启用<webview>、理解其 OOPIF 内部实现与安全模型、熟练配置全部 14 个标签属性、调用其 60+ 方法与 40+ 个 DOM 事件,并了解其局限性与替代方案(iframe、WebContentsView)。
⚠️ 使用警告:官方不推荐优先使用 <webview>
Electron 的 webview 标签基于 Chromium 的 webview,而 Chromium 侧正在经历剧烈的架构变迁,这会影响 webview 的稳定性,包括渲染、导航与事件路由等方面。官方当前建议不要使用 webview 标签,优先考虑以下替代方案:
- 普通
<iframe>; WebContentsView;- 一种完全避免嵌入内容的整体架构。
若你评估后仍需要 webview 的能力(例如需要隔离的独立进程、自定义协议或与 Chromium webview 语义兼容的存量应用),再继续阅读本文。
启用 <webview> 标签
webview 标签在 Electron >= 5 中默认关闭。你需要在使用 BrowserWindow 构造窗口时设置 webPreferences.webviewTag 为 true:
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
webPreferences: {
webviewTag: true // 显式开启 <webview>
}
})
从源码看,该选项的默认值是 false:lib/browser/guest-window-manager.ts 中创建 guest 窗口时 webviewTag: false;而主进程侧在 shell/browser/web_contents_preferences.cc 会通过 web_preferences.Get(options::kWebviewTag, &webview_tag_) 读取该开关,并在渲染进程偏好中下发。
渲染进程是否真正注册 <webview> 自定义元素,由 lib/renderer/common-init.ts 读取 webviewTag 后调用 webViewInit 决定:
- 只有
webviewTag === true且当前页面本身不是 webview guest 时,才会执行注册逻辑——这一检查来自 lib/renderer/web-view/web-view-init.ts,其注释明确说明 "Don't allow recursive<webview>",即禁止在 webview 内再嵌套 webview; - 当页面启用了
contextIsolation时,guestViewInternal 桥接对象通过v8Util.setHiddenValue存放在 window 隐藏属性中,由隔离世界的初始化代码 lib/isolated_renderer/init.ts 调用同一套setupWebView完成注册。
注册动作本身发生在 lib/renderer/web-view/web-view-element.ts:在允许的特殊作用域内调用 window.customElements.define('webview', WebViewElement),同时暴露 window.WebView,并删除 connectedCallback / disconnectedCallback / observedAttributes 等生命周期钩子,防止开发者自行调用产生未预期行为。
概览:隔离进程中的“客座内容”
在一个隔离的 frame 与进程中显示外部 Web 内容。
- 进程:Renderer(渲染进程)
- 该类不从
'electron'模块导出,只能作为 DOM 上<webview>元素实例使用。
webview 用于把"访客"内容(guest content,例如其他网页)嵌入到 Electron 应用中。guest 内容被限制在 webview 容器内部;应用内的嵌入页(embedder page)控制 guest 内容的布局与渲染方式。
与 <iframe> 的关键区别在于:
<webview>与应用运行在不同的进程中;- 它不拥有你的网页同样的权限;
- 应用与嵌入内容之间的所有交互都是异步的。
这使你的应用免于被嵌入内容攻击。
[!NOTE] 大多数从宿主页面调用到 webview 上的方法,都需要同步调用到主进程。具体来说,宿主页面方法经由
guestViewInternal.invokeSync(...)(同步方法)或invoke(...)(异步方法)走 IPC 到达主进程侧的 guest 管理器执行,见 lib/renderer/web-view/web-view-impl.ts。
最小示例
在最简单的形式里,webview 标签包含目标网页的 src 以及控制容器外观的 CSS:
<webview id="foo" src="https://www.github.com/" style="display:inline-flex; width:640px; height:480px"></webview>
若希望以任何方式控制 guest 内容,可以编写 JavaScript 监听 webview 事件并通过方法响应。下面的例子注册了两个事件监听器:一个监听页面开始加载、一个监听页面停止加载,加载期间显示 "loading..." 提示:
<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>
内部实现:基于 OOPIF 与 Shadow DOM
在底层,webview 基于 Out-of-Process iframes (OOPIF) 实现。webview 标签本质上是一个自定义元素(custom element),它使用 Shadow DOM 在内部包裹一个 <iframe> 元素。
仓库的渲染层源码完整印证了这一描述。查看 lib/renderer/web-view/web-view-element.ts:WebViewElement extends HTMLElement,observedAttributes 中列出全部可观测属性;而 lib/renderer/web-view/web-view-impl.ts 的构造函数里:
const shadowRoot = this.webviewNode.attachShadow({ mode: 'open' });
const style = shadowRoot.ownerDocument.createElement('style');
style.textContent = ':host { display: flex; }';
shadowRoot.appendChild(style);
...
const iframeElement = document.createElement('iframe');
iframeElement.style.flex = '1 1 auto';
iframeElement.style.width = '100%';
iframeElement.style.border = '0';
可见 <webview> 正是"自定义元素 + open shadow root + 内部 iframe"的组合,并设置了 :host { display: flex; } 样式。此外每个 WebViewImpl 会通过 hooks.setIsWebView(iframeElement)(见 lib/renderer/web-view/web-view-init.ts)把内部 iframe 标记为 webview frame,Chromium 侧 RendererClientBase::IsWebViewFrame 据此识别,从而把该 frame 交给独立的 guest 进程处理。
因此,webview 的行为与跨域 iframe 非常相似,例如:
- 点击进入
webview时,页面焦点会从嵌入者 frame 移入webview; - 不能为
webview添加键盘、鼠标与滚轮事件监听器(这些输入直接作用于其内部渲染进程); - 嵌入者 frame 与
webview之间的所有交互都是异步的。
CSS 样式注意
请勿覆盖 <webview> 标签内部的 display:flex; 默认样式(除非按文档示例使用 display:inline-flex; 做行内布局)。该内部样式用于保证子 iframe 在传统布局与 flexbox 布局下都能撑满 webview 容器的全部宽高。
标签属性(Tag Attributes)
<webview> 支持以下属性。综合 lib/renderer/web-view/web-view-constants.ts 与 lib/renderer/web-view/web-view-element.ts 可确认,被 MutationObserver 观测并参与建 guest 参数的属性恰为以下 14 个;boolean 类型属性"存在即 true"(详见 lib/renderer/web-view/web-view-attributes.ts 中 BooleanAttribute 的 hasAttribute 取值逻辑)。
src
<webview src="https://www.github.com/"></webview>
类型 string,表示当前可见 URL。向该属性写入值会触发顶层导航;给 src 赋与当前相同的值会重新加载当前页面。src 也接受 data URL,例如 data:text/plain,Hello, world!。属性变更由 SrcAttribute(lib/renderer/web-view/web-view-attributes.ts)处理,读取时会基于 location.href 解析为绝对 URL。
nodeintegration
<webview src="https://www.google.com/" nodeintegration></webview>
类型 boolean。存在时 guest 页面会启用 Node 集成,可以使用 require、process 等 Node API 访问底层系统资源。guest 页面默认关闭 Node 集成。出于安全考虑,务必仅在受信任内容上开启。
nodeintegrationinsubframes
<webview src="https://www.google.com/" nodeintegrationinsubframes></webview>
类型 boolean,实验性选项,用于在 webview 内部的子 frame(如其中嵌套的 iframe)启用 NodeJS 支持。启用后,你的 preload 脚本会在每个 iframe 中加载,可在脚本中用 process.isMainFrame 判断当前是否为主 frame。guest 页面默认关闭。
plugins
<webview src="https://www.github.com/" plugins></webview>
类型 boolean。存在时 guest 页面可以使用浏览器插件(plugin)。插件默认禁用。
preload
<!-- 从普通文件加载 -->
<webview src="https://www.github.com/" preload="./test.js"></webview>
<!-- 或从 asar 归档加载 -->
<webview src="https://www.github.com/" preload="./app.asar/test.js"></webview>
类型 string,指定在 guest 页面其他脚本运行前加载的脚本。脚本 URL 的协议必须是 file:(即便使用 asar: 归档),因为它在底层由 Node 的 require 加载,而 require 会把 asar: 归档当作虚拟目录处理。
当 guest 页面没有启用 node 集成时,该脚本仍能访问全部 Node API,但在脚本执行结束后,Node 注入的全局对象会被删除。
httpreferrer
<webview src="https://www.github.com/" httpreferrer="https://example.com/"></webview>
类型 string,为 guest 页面设置 referrer URL。
useragent
<webview src="https://www.github.com/" useragent="Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko"></webview>
类型 string,在页面导航之前设置 guest 页面的 user agent。页面加载完成后如需修改,应改用 setUserAgent 方法。
disablewebsecurity
<webview src="https://www.github.com/" disablewebsecurity></webview>
类型 boolean。存在时 guest 页面将关闭 Web 安全(跨域限制等);Web 安全默认开启。该值只能在第一次导航前修改。
partition
<webview src="https://github.com" partition="persist:github"></webview>
<webview src="https://electronjs.org" partition="electron"></webview>
类型 string,设置页面使用的 session(会话)。
- 若
partition以persist:开头,页面使用持久化 session,应用内所有相同partition的页面共享该会话; - 若无
persist:前缀,页面使用内存 session; - 为多个页面分配相同
partition,它们即可共享同一会话; - 未设置
partition时使用应用默认 session。
由于活动渲染进程的 session 无法更改,该值只能在第一次导航前修改;之后再次修改会抛出 DOM 异常。这一约束同样体现在渲染层:lib/renderer/web-view/web-view-attributes.ts 中 PartitionAttribute.handleMutation 会检查 beforeFirstNavigation,一旦已经导航过就会打印错误并回滚旧值;而 partition="persist:"(空名)会被判定为非法。
allowpopups
<webview src="https://www.github.com/" allowpopups></webview>
类型 boolean。存在时 guest 页面被允许打开新窗口。弹窗默认禁用。
webpreferences
<webview src="https://github.com" webpreferences="allowRunningInsecureContent, javascript=no"></webview>
类型 string,逗号分隔的字符串列表,用于设置在 webview 上的 web 偏好。完整支持列表见 BrowserWindow 构造选项。
该字符串与 window.open 的 features 字符串采用相同格式:
- 单独出现的名字按布尔值
true处理; - 通过
=加值可为偏好指定其他值,如javascript=no; - 特殊值
yes、1解释为true;no、0解释为false。
仓库中负责解析的是 lib/browser/parse-features-string.ts(parseCommaSeparatedKeyValue / parseWebViewWebPreferences),其 coerce 函数正是按照上述规则把 true/1/yes 归并为 true、false/0/no 归并为 false。
安全关键偏好不能把 guest 变得比其 embedder 更不安全:当 embedder 在 contextIsolation、javascript、nodeIntegration、nodeIntegrationInWorker、sandbox、nodeIntegrationInSubFrames 或 enableWebSQL 中的任一设置为更安全的值时,guest 会继承该安全值,对应 webpreferences 项会被忽略。
enableblinkfeatures
<webview src="https://www.github.com/" enableblinkfeatures="PreciseMemoryInfo, CSSVariables"></webview>
类型 string,逗号分隔的字符串列表,指定启用的 Blink 特性。完整支持列表见 RuntimeEnabledFeatures.json5(Chromium 源文件)。
disableblinkfeatures
<webview src="https://www.github.com/" disableblinkfeatures="PreciseMemoryInfo, CSSVariables"></webview>
类型 string,逗号分隔的字符串列表,指定禁用的 Blink 特性。支持列表同上。
方法(Methods)
<webview> 元素暴露以下方法。方法调用前 webview 元素必须已经加载完成(通常先等待 dom-ready 事件)。
示例
const webview = document.querySelector('webview')
webview.addEventListener('dom-ready', () => {
webview.openDevTools()
})
从源码角度,宿主页面可调用的方法被分成了"同步方法"与"异步方法"两组(见 lib/common/web-view-methods.ts),在 lib/renderer/web-view/web-view-impl.ts 中通过 guestViewInternal.invokeSync(...) / invoke(...) 统一转发到主进程。此外还有一组可通过属性读写访问的 properties(audioMuted、userAgent、zoomLevel、zoomFactor、zoomMode、frameRate)。同步方法包括:
getURL、getTitle、isLoading、isLoadingMainFrame、isWaitingForResponse、stop、reload、reloadIgnoringCache、isCrashed、setUserAgent、getUserAgent、openDevTools、closeDevTools、isDevToolsOpened、isDevToolsFocused、inspectElement、setAudioMuted、isAudioMuted、isCurrentlyAudible、undo、redo、cut、copy、centerSelection、paste、pasteAndMatchStyle、delete、selectAll、unselect、scrollToTop、scrollToBottom、adjustSelection、replace、replaceMisspelling、findInPage、stopFindInPage、downloadURL、inspectSharedWorker、inspectServiceWorker、showDefinitionForSelection、getZoomFactor、getZoomLevel、setZoomFactor、setZoomLevel,以及导航历史组 canGoBack、canGoForward、canGoToOffset、clearHistory、goBack、goForward、goToIndex、goToOffset。
异步方法包括:
capturePage、loadURL、executeJavaScript、insertCSS、insertText、removeInsertedCSS、send、sendToFrame、sendInputEvent、setLayoutZoomLevelLimits、setVisualZoomLevelLimits、print、printToPDF。
下文按用途分组给出完整签名与语义。
导航与页面加载
<webview>.loadURL(url[, options])
urlURLoptionsObject(可选)httpReferrer(string | Referrer)(可选)— HTTP Referrer URLuserAgentstring(可选)— 发起请求的 user agentextraHeadersstring(可选)— 以"\n"分隔的额外请求头postData(UploadRawData | UploadFile)[](可选)baseURLForDataURLstring(可选)— 供 data URL 加载其他文件时使用的 base url(需带尾部路径分隔符);仅在url是 data URL 且需加载其他文件时需要
返回 Promise<void> — 页面加载完成(见 did-finish-load 事件)时 resolve,加载失败(见 did-fail-load 事件)时 reject。在 webview 中加载 url,url 必须包含协议前缀,如 http:// 或 file://。
<webview>.downloadURL(url[, options])
urlstringoptionsObject(可选)headersRecord<string, string>(可选)— HTTP 请求头
在不发生导航的情况下发起对 url 资源的下载。
页面状态查询
<webview>.getURL()返回string— guest 页面的 URL。<webview>.getTitle()返回string— guest 页面的标题。<webview>.isLoading()返回boolean— guest 页面是否仍在加载资源。<webview>.isLoadingMainFrame()返回boolean— 主 frame(而不只是其中的 iframe 等子 frame)是否仍在加载。<webview>.isWaitingForResponse()返回boolean— guest 页面是否正在等待页面主资源的首个响应。<webview>.getWebContentsId()返回number— 该 webview 的 WebContents ID(元素尚未 attach 时会抛出错误,见 lib/renderer/web-view/web-view-element.ts)。
停止与刷新
<webview>.stop()— 停止任何进行中的导航。<webview>.reload()— 重新加载 guest 页面。<webview>.reloadIgnoringCache()— 忽略缓存地重新加载 guest 页面。<webview>.isCrashed()返回boolean— 渲染进程是否已崩溃。
导航历史
<webview>.canGoBack()返回boolean— 是否可后退。<webview>.canGoForward()返回boolean— 是否可前进。<webview>.canGoToOffset(offset),offsetInteger — 返回boolean,是否可以跳到offset。<webview>.clearHistory()— 清空导航历史。<webview>.goBack()— 后退。<webview>.goForward()— 前进。<webview>.goToIndex(index),indexInteger — 导航到指定的绝对索引。<webview>.goToOffset(offset),offsetInteger — 从"当前条目"导航到指定的偏移位置。
User Agent
<webview>.setUserAgent(userAgent),userAgentstring — 覆盖 guest 页面的 user agent。<webview>.getUserAgent()返回string— 获取 guest 页面的 user agent。
CSS 注入
<webview>.insertCSS(css),cssstring — 返回Promise<string>:向当前页面注入 CSS,resolve 出可用于后续移除的样式表 key。<webview>.removeInsertedCSS(key),keystring — 返回Promise<void>:按insertCSS返回的 key 移除注入的样式表,移除成功时 resolve。
JavaScript 执行
<webview>.executeJavaScript(code[, userGesture])
codestringuserGestureboolean(可选)— 默认false
返回 Promise<any> — resolve 为代码执行结果;若代码结果为 rejected promise 则 reject。在页面内执行 code。若设置 userGesture,会在页面内创建用户手势上下文,像 requestFullScreen 这类需要用户操作的 HTML API 可借助该选项完成自动化。
DevTools
<webview>.openDevTools()— 打开 guest 页面的 DevTools 窗口。<webview>.closeDevTools()— 关闭 guest 页面的 DevTools 窗口。<webview>.isDevToolsOpened()返回boolean— guest 页面是否已挂接 DevTools 窗口。<webview>.isDevToolsFocused()返回boolean— guest 页面的 DevTools 窗口是否聚焦。<webview>.inspectElement(x, y),x/yInteger — 开始检查 guest 页面(x, y)位置处的元素。<webview>.inspectSharedWorker()— 打开 guest 页面中 shared worker 上下文的 DevTools。<webview>.inspectServiceWorker()— 打开 guest 页面中 service worker 上下文的 DevTools。
音频控制
<webview>.setAudioMuted(muted),mutedboolean — 静音/取消静音 guest 页面。<webview>.isAudioMuted()返回boolean— guest 页面是否被静音。<webview>.isCurrentlyAudible()返回boolean— 当前是否有音频正在播放。
文本编辑命令(Editing Commands)
以下方法在页面内执行对应编辑命令:
<webview>.undo()— 撤销<webview>.redo()— 重做<webview>.cut()— 剪切<webview>.copy()— 复制<webview>.centerSelection()— 将当前文本选区居中<webview>.paste()— 粘贴<webview>.pasteAndMatchStyle()— 匹配样式粘贴<webview>.delete()— 删除<webview>.selectAll()— 全选<webview>.unselect()— 取消选择<webview>.replace(text),textstring — 替换<webview>.replaceMisspelling(text),textstring — 替换拼写错误的词<webview>.insertText(text),textstring — 返回Promise<void>,向当前聚焦元素插入text<webview>.scrollToTop()— 滚动到当前<webview>顶部<webview>.scrollToBottom()— 滚动到当前<webview>底部
<webview>.adjustSelection(options)
optionsObjectstartNumber(可选)— 当前选区起始索引的位移量endNumber(可选)— 当前选区结束索引的位移量
以给定位移量调整聚焦 frame 中当前文本选区的起点与终点。负值向文档开头移动,正值向文档结尾移动。示例见 webContents.adjustSelection。
页面内查找
<webview>.findInPage(text[, options])
textstring — 要搜索的内容,不能为空optionsObject(可选)forwardboolean(可选)— 向前或向后查找,默认truefindNextboolean(可选)— 本次请求是否开启新的查找会话;初次请求应为true,后续请求为false,默认falsematchCaseboolean(可选)— 是否区分大小写,默认false
返回 Integer — 本次请求的 request id。启动一次页面内查找;结果通过订阅 found-in-page 事件获取。
<webview>.stopFindInPage(action)
actionstring — 结束findInPage请求时执行的动作:clearSelection— 清除选区keepSelection— 将选区转换为普通选区activateSelection— 聚焦并点击选中节点
以指定 action 停止 webview 中任何进行中的 findInPage 请求。
打印与截图
<webview>.print([options])
optionsObject(可选)silentboolean(可选)— 不向用户询问打印设置,默认falseprintBackgroundboolean(可选)— 打印背景色与背景图,默认falsedeviceNamestring(可选)— 打印机设备名,须为系统定义名而非“友好”名,例如'Brother_QL_820NWB'而非'Brother QL-820NWB'colorboolean(可选)— 彩色或灰度打印,默认truemarginsObject(可选)marginTypestring(可选)— 可为default、none、printableArea或custom;选custom时需同时指定top、bottom、left、righttop/bottom/left/rightnumber(可选)— 打印页边距(像素)
landscapeboolean(可选)— 横向打印,默认falsescaleFactornumber(可选)— 缩放比例pagesPerSheetnumber(可选)— 每张纸打印的页数collateboolean(可选)— 是否逐份打印copiesnumber(可选)— 打印份数pageRangesObject[](可选)— 打印页码范围fromnumber — 首页索引(0 起)tonumber — 末页索引(含,0 起)
duplexModestring(可选)— 双面模式:simplex、shortEdge或longEdgedpiRecord<string, number>(可选)—horizontal/vertical分别为水平、垂直 dpiheaderstring(可选)— 打印为页眉的字符串footerstring(可选)— 打印为页脚的字符串pageSizestring | Size(可选)— 打印纸张大小:A3、A4、A5、Legal、Letter、Tabloid,或含height(微米)的对象usePrinterDefaultPageSizeboolean(可选)— 使用系统默认纸型,默认false;不能与pageSize同时使用。给出deviceName时用该打印机默认纸型,否则用系统默认打印机纸型;无法获取时回退 A4 (210mm × 297mm)
返回 Promise<void>。打印 webview 页面,与 webContents.print([options]) 等价。
<webview>.printToPDF(options)
optionsPrintToPDFOptions
返回 Promise<Uint8Array> — resolve 出生成的 PDF 数据。将 webview 页面打印为 PDF,与 webContents.printToPDF(options) 等价。
<webview>.capturePage([rect])
rectRectangle(可选)— 捕获的页面区域
返回 Promise<NativeImage> — resolve 出一个 NativeImage。捕获 rect 内页面的快照;省略 rect 捕获整个可见页面。
消息通信
<webview>.send(channel, ...args)
channelstring...argsany[]
返回 Promise<void>。通过 channel 向渲染进程发送异步消息,可携带任意参数;渲染进程通过 ipcRenderer 监听 channel 事件处理消息。示例见 webContents.send。
<webview>.sendToFrame(frameId, channel, ...args)
frameId[number, number] —[processId, frameId]channelstring...argsany[]
返回 Promise<void>。与 send 类似但可定向到指定 frame。示例见 webContents.sendToFrame。
输入事件
<webview>.sendInputEvent(event)
返回 Promise<void>。向页面发送一个输入事件。event 对象详细说明见 webContents.sendInputEvent。
缩放
<webview>.setZoomFactor(factor),factornumber — 把缩放因子设为指定值。缩放因子 = 缩放百分比 ÷ 100,所以 300% = 3.0。<webview>.setZoomLevel(level),levelnumber — 把缩放级别设为指定值。原始大小是 0,每增减 1 级代表放大/缩小 20%,默认限制为原大小的 300% 与 50%。公式为scale := 1.2 ^ level。
[!NOTE] Chromium 层的缩放策略是 same-origin:同一域名设置的缩放级别会传播到所有包含同域名的窗口实例。让窗口 URL 各不相同,即可实现按窗口缩放。
<webview>.getZoomFactor()返回number— 当前缩放因子。<webview>.getZoomLevel()返回number— 当前缩放级别。<webview>.setVisualZoomLevelLimits(minimumLevel, maximumLevel),参数为 number — 返回Promise<void>,设置双指捏合缩放的上下限。
其他
<webview>.showDefinitionForSelection()macOS — 显示查询页面所选单词的弹出词典。
DOM 事件
以下 DOM 事件对 <webview> 元素可用。除 load-commit、-focus-change 等由渲染层合成转发外,多数事件由主进程根据 guest WebContents 的回调派发,最终由 lib/renderer/web-view/web-view-impl.ts 的 dispatchEvent 转成普通 DOM 事件在 webview 节点上触发(参数被 Object.assign 到 event 上)。此外每个事件还可通过 on<event> 属性风格绑定(setupEventProperty,见 lib/renderer/web-view/web-view-impl.ts)。
导航与加载生命周期
load-commit— 返回urlstring、isMainFrameboolean。一次加载提交时触发,包括当前文档内的导航以及子 frame 的 document 级加载,但不包括异步资源加载。主 frame 的 load-commit 还会让渲染层回写src属性(onLoadCommit)。did-finish-load— 导航完成时触发,即标签页转圈动画停止且onload事件派发。did-fail-load— 返回errorCodeInteger、errorDescriptionstring、validatedURLstring、isMainFrameboolean。与did-finish-load类似,但在加载失败或被取消时触发(例如调用了window.stop())。did-frame-finish-load— 返回isMainFrameboolean。某个 frame 完成导航时触发。did-start-loading— 对应标签页转圈动画开始的时刻。did-stop-loading— 对应标签页转圈动画停止的时刻。dom-ready— 指定 frame 中的 document 加载完成时触发。did-attach— 附着(attach)到 embedder web contents 时触发。
页面标题与图标
page-title-updated— 返回titlestring、explicitSetboolean。导航期间设置页面标题时触发;当标题是从文件 URL 合成时explicitSet为false。page-favicon-updated— 返回faviconsstring[](URL 数组)。页面收到 favicon URL 时触发。did-change-theme-color— 返回themeColorstring。页面主题色改变时触发,通常因遇到如下 meta 标签:
<meta name='theme-color' content='#ff0000'>
全屏
enter-html-full-screen— 页面通过 HTML API 进入全屏时触发。leave-html-full-screen— 页面通过 HTML API 退出全屏时触发。
控制台消息
console-message— 返回levelInteger(0~3,依次对应verbose、info、warning、error)、messagestring(实际控制台消息)、lineInteger(触发该消息的源码行号)、sourceIdstring。guest 窗口记录控制台消息时触发。以下示例把所有日志消息转发到 embedder 控制台(不区分级别):
const webview = document.querySelector('webview')
webview.addEventListener('console-message', (e) => {
console.log('Guest page logged a message:', e.message)
})
页面内查找结果
found-in-page— 返回resultObject:requestIdIntegeractiveMatchOrdinalInteger — 当前活动匹配的位置matchesInteger — 匹配总数selectionAreaRectangle — 首个匹配区域坐标finalUpdateboolean
当 webview.findInPage 请求有结果可用时触发。
const webview = document.querySelector('webview')
webview.addEventListener('found-in-page', (e) => {
webview.stopFindInPage('keepSelection')
})
const requestId = webview.findInPage('test')
console.log(requestId)
导航相关事件
will-navigate— 返回urlstring。当用户或页面想要开始导航时触发,例如window.location对象改变或用户点击页面内链接。使用loadURL、back等 API 编程式启动的导航不会触发该事件;页内导航(点击锚点链接或更新window.location.hash)也不触发,应改用did-navigate-in-page。调用event.preventDefault()无效。will-frame-navigate— 返回urlstring、isMainFrameboolean、frameProcessIdInteger、frameRoutingIdInteger。当用户或页面想要在<webview>或其内嵌的任何 frame 中开始导航时触发。触发/不触发情形与will-navigate相同,preventDefault()同样无效。did-start-navigation— 返回urlstring、isInPlaceboolean、isMainFrameboolean、frameProcessIdInteger、frameRoutingIdInteger。任何 frame(含主 frame)开始导航时触发;页内导航的isInPlace为true。did-redirect-navigation— 返回参数同did-start-navigation。导航期间发生服务端重定向(如 302)后触发。did-navigate— 返回urlstring。一次导航完成时触发。页内导航不触发,应使用did-navigate-in-page。did-frame-navigate— 返回urlstring、httpResponseCodeInteger(非 HTTP 导航为 -1)、httpStatusTextstring(非 HTTP 导航为空)、isMainFrameboolean、frameProcessIdInteger、frameRoutingIdInteger。任意 frame 的导航完成时触发,页内导航不触发。did-navigate-in-page— 返回isMainFrameboolean、urlstring。页内导航发生时触发——页面 URL 变化但不触发页面外导航,例如点击锚点链接或触发 DOMhashchange事件时。
窗口关闭与渲染进程
close— guest 页面尝试关闭自身时触发。以下示例在 guest 尝试自关时把 webview 导航到about:blank:
const webview = document.querySelector('webview')
webview.addEventListener('close', () => {
webview.src = 'about:blank'
})
render-process-gone— 返回detailsRenderProcessGoneDetails。渲染进程意外消失时触发,通常是被崩溃或被杀。destroyed— WebContents 被销毁时触发。
媒体
media-started-playing— 媒体开始播放时触发。media-paused— 媒体暂停或播放完毕时触发。
链接预览与 DevTools
update-target-url— 返回urlstring。鼠标移到链接上或键盘将焦点移到链接上时触发。devtools-open-url— 返回urlstring。在 DevTools 中点击链接,或在其右键菜单中对链接选择 "Open in new tab" 时触发。devtools-search-query— 返回querystring。在右键菜单中对其文本选择 "Search" 时触发。devtools-opened— DevTools 打开时触发。devtools-closed— DevTools 关闭时触发。devtools-focused— DevTools 聚焦/打开时触发。
embedder 与 guest 通信
ipc-message— 返回frameId[number, number]([processId, frameId]对)、channelstring、argsany[]。guest 页面向 embedder 页面发送异步消息时触发。
配合 sendToHost 方法与 ipc-message 事件即可在 guest 与 embedder 之间双向通信:
// In embedder page.
const webview = document.querySelector('webview')
webview.addEventListener('ipc-message', (event) => {
console.log(event.channel)
// Prints "pong"
})
webview.send('ping')
// In guest page.
const { ipcRenderer } = require('electron')
ipcRenderer.on('ping', () => {
ipcRenderer.sendToHost('pong')
})
右键菜单
context-menu— 返回paramsObject。出现需要处理的新右键菜单时触发,参数非常丰富:x/yInteger — 坐标linkURLstring — 触发菜单所在节点外层链接的 URLlinkTextstring — 链接关联文本;若链接内容是图片则可能为空字符串pageURLstring — 触发菜单所在顶层页面的 URLframeURLstring — 触发菜单所在子 frame 的 URLsrcURLstring — 触发菜单元素的源 URL(有源 URL 的元素包括图片、音频与视频)mediaTypestring — 节点类型:none、image、audio、video、canvas、file或pluginhasImageContentsboolean — 是否在含非空内容的图片上触发isEditableboolean — 上下文是否可编辑selectionTextstring — 触发菜单的选区文本titleTextstring — 触发菜单选区的 title 文本altTextstring — 触发菜单选区的 alt 文本suggestedFilenamestring — 通过右键菜单 "Save Link As" 保存文件时建议的文件名selectionRectRectangle — 文档坐标系中选区范围的矩形selectionStartOffsetnumber — 选区文本的起始位置referrerPolicyReferrer — 触发菜单所在 frame 的 referrer policymisspelledWordstring — 光标下的拼写错误单词(若有)dictionarySuggestionsstring[] — 用于替换misspelledWord的建议词数组;仅当存在拼写错误词且启用拼写检查时可用frameCharsetstring — 触发菜单所在 frame 的字符编码formControlTypestring — 触发菜单的来源控件类型,可能值包括none、button-button、field-set、input-button、input-checkbox、input-color、input-date、input-datetime-local、input-email、input-file、input-hidden、input-image、input-month、input-number、input-password、input-radio、input-range、input-reset、input-search、input-submit、input-telephone、input-text、input-time、input-url、input-week、output、reset-button、select-list、select-multiple、select-one、submit-button与text-areaspellcheckEnabledboolean — 若上下文可编辑,是否启用拼写检查menuSourceTypestring — 触发右键菜单的输入来源:none、mouse、keyboard、touch、touchMenu、longPress、longTap、touchHandle、stylus、adjustSelection或adjustSelectionResetmediaFlagsObject — 触发菜单的媒体元素标志:inErrorboolean — 媒体元素是否已崩溃isPausedboolean — 是否暂停isMutedboolean — 是否静音hasAudioboolean — 是否有音频isLoopingboolean — 是否循环isControlsVisibleboolean — 控件是否可见canToggleControlsboolean — 控件是否可切换canPrintboolean — 是否可打印canSaveboolean — 是否可下载canShowPictureInPictureboolean — 是否可画中画isShowingPictureInPictureboolean — 当前是否在画中画canRotateboolean — 是否可旋转canLoopboolean — 是否可循环
editFlagsObject — 渲染进程自认能执行对应操作的能力标志:canUndo/canRedo/canCut/canCopy/canPaste/canDelete/canSelectAllboolean — 是否能执行对应编辑动作canEditRichlyboolean — 是否能富文本编辑
总结与建议
综合文档与源码,<webview> 提供了一套相当完整的"应用内嵌外部内容"能力矩阵:
- 隔离性:guest 运行在独立进程与独立 frame,默认无 Node 集成、无插件、无弹窗,配合
partition可精细控制会话边界; - 可控性:导航、历史、缩放、打印、DevTools、音频、页面查找、CSS/JS 注入、双向 IPC 一应俱全;
- 可观测性:从导航生命周期、控制台、右键菜单到渲染进程崩溃等各类 DOM 事件覆盖了绝大多数调试与功能场景。
在决定技术选型时,请务必再次权衡官方警告:受 Chromium webview 架构持续演进的稳定性影响,优先评估 <iframe>、WebContentsView 等替代方案。若坚持使用,建议将 webview 相关页面集中在少数受控场景,并参考仓库测试 spec/webview-spec.ts 与 webview-tag API 结构定义 里没有覆盖到的运行时细节前,先在目标 Electron 版本上做充分验证。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00