# 24.2.`<webview>` 标签
> 在一个单独的 frame 和 进程中显示外部 web 内容。
使用 `webview` 标签来嵌入'guest' 内容 (比如 web 页面)到你的 Electron 应用。这个访客内容包含在 `webview` 容器内。
应用中一个嵌入的页面控制访客内容如何陈列和渲染。
不像一个 `iframe` , `webview` 运行在一个相对你的 app 独立的进程中。在你的 app 中,它和你的 web 页面并没有相同的权限,并且所有你的应用和嵌入内容之间的交互都会是异步的。这使得你的应用从嵌入内容之间保持安全。
出于安全目的, `webview` 只能被用在启用了 `nodeIntegration` 的 `BrowserWindow` 中。
## 示例
要嵌入一个 web 页面到你的 app ,添加 `webview` 标签到 app 的嵌入页面(指app 中用于显示访客内容的页面)。以这种简单的形式, `webview` 标签包含了 web 页面的 `src` 和控制 `webview`容器外观的 css 样式:
```html
<webview id="foo" src="https://www.github.com/" style="display:inline-flex; width:640px; height:480px"></webview>
```
如果你想以某种方式控制访客内容,可以编写监听 `webview` 事件的 JavaScript ,并使用 `webview` 的方法响应这些事件。这里是两个监听器的示例代码:一个监听 web 页面开始载入,另一个监听 web 页面停止加载,并在载入过程中显示一个 "loading..." 消息:
```html
<script>
onload = () => {
const webview = document.getElementById('foo')
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>
```
## CSS 样式注意
注意,当使用传统的和适应的布局(从 v 0.36.11起), `webview` 标签的样式在内部使用 `display:flex;` 来确保子 `object` 元素填充完整的 `webview` 容器的宽高度。不要覆盖默认的 `display:flex;` CSS 属性,除非对于内联布局声明 `display:inline-flex;` 。
`webview` 在被使用 `hidden` 属性或使用 `display: none;` 隐藏时会有些问题。这可能在它的子 `browserplugin` 对象中引发不常见的渲染行为,而且 web 页面被重载,当 `webview` 未被隐藏,而不仅是再次可见。建议的方案是使用 CSS 置 0 `webview` 的宽度和高度来隐藏它, 并允许元素通过 `flex` 缩小到 0 范围。
```html
<style>
webview {
display:inline-flex;
width:640px;
height:480px;
}
webview.hide {
flex: 0 1;
width: 0px;
height: 0px;
}
</style>
```
## 标签属性
`webview` 标签有以下属性:
### `src`
```html
<webview src="https://www.github.com/"></webview>
```
返回可见的 URL 。写到这个属性初始化顶部导航。
赋值 `src` 它自己的值将会重新载入当前页面。.
`src` 属性也可以接受 data URLs,如
`data:text/plain,Hello, world!`.
### `autosize`
```html
<webview src="https://www.github.com/" autosize="on" minwidth="576" minheight="432"></webview>
```
如果为 "on", `webview` 容器会自动根据属性 `minwidth`,`minheight`, `maxwidth` 和
`maxheight` 指定的边界内自动重设大小。这些约束不影响 `webview` ,除非 `autosize` 被启用。当 `autosize` 被启用, `webview` 容器尺寸不能小于最小值或大于最大值。
### `nodeintegration`
```html
<webview src="http://www.google.com/" nodeintegration></webview>
```
如果为 "on",`webview` 中的访客页面将有 node 集成,并可以使用 node APIs,像 `require` 和 `process` 来访问底层系统资源。
### `plugins`
```html
<webview src="https://www.github.com/" plugins></webview>
```
如果开启,`webview` 中的访客页面可以使用浏览器插件。
### `preload`
```html
<webview src="https://www.github.com/" preload="./test.js"></webview>
```
指定一个脚本,将会在运行于访客页面中的其它脚本被载入之前加载。脚本的 URL 协议必须是 `file:` 或者 `asar:`,因为它在表面之下将被通过 `require` 加载到访客页面。
当访客页面没有 node 集成,这个脚本仍然有权限访问所有 Node APIs,但是被 Node 注入的全局对象会在这个脚本执行完成之后删除。
### `httpreferrer`
```html
<webview src="https://www.github.com/" httpreferrer="http://cheng.guru"></webview>
```
设置访客页面的 referrer URL。
### `useragent`
```html
<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>
```
在页面被导航之前设置访客页面的用户代理。一旦页面被加载,使用 `setUserAgent` 方法来改变用户代理。
### `disablewebsecurity`
```html
<webview src="https://www.github.com/" disablewebsecurity></webview>
```
如果开启,访客页面 web安全将被禁用。
### `partition`
```html
<webview src="https://github.com" partition="persist:github"></webview>
<webview src="http://electron.atom.io" partition="electron"></webview>
```
设置页面使用的会话。如果 `partition` 以 `persist:` 开始,页面会使用一个持续可用的会话到 app 中所有使用相同 `partition` 的页面。如果没有 `persist:` 前缀,页面会使用一个内存中的会话。通过分配相同的 `partition`,多个页面可以共享相同的会话。如果 `partition` 未设置,那么应用默认的会话被使用。
这个值只能在第一次导航之前被修改,因为一个活动渲染器进程的会话不能改变。后续的修改这个值的企图会失败,抛出一个 DOM 异常。
### `allowpopups`
```html
<webview src="https://www.github.com/" allowpopups></webview>
```
如果开启,访客页面会被允许打开新窗口。
### `webpreferences`
```html
<webview src="https://github.com" webpreferences="allowDisplayingInsecureContent, javascript=no"></webview>
```
一个字符串列表,指定设置 `webview` 上的 web 首选项,通过`,` 分隔。
支持的首选项完整列表可以在 [BrowserWindow](browser-window.md#new-browserwindowoptions) 中查看。
字符串依照和作为在 `window.open` 中的功能相同的格式。
一个名字本身被给定一个 `true` 的布尔值。
一个首选项可以通过 `=` 设置为另一个值。
特别的值 `yes` 和 `1` 被解释为 `true`,而 `no` 和 `0` 被解释为 `false`。
### `blinkfeatures`
```html
<webview src="https://www.github.com/" blinkfeatures="PreciseMemoryInfo, CSSVariables"></webview>
```
指定 blink 功能被启用的一个字符串列表,使用 `,` 分隔。
支持功能的字符串完整列表可以在 [RuntimeEnabledFeatures.in][blink-feature-string] 文件中找到。
### `disableblinkfeatures`
```html
<webview src="https://www.github.com/" disableblinkfeatures="PreciseMemoryInfo, CSSVariables"></webview>
```
指定 blink 功能被禁用的字符串列表,使用 `,` 分隔。
支持功能的字符串完整列表可以在 [RuntimeEnabledFeatures.in][blink-feature-string] 文件中找到。
### `guestinstance`
```html
<webview src="https://www.github.com/" guestinstance="3"></webview>
```
连接 `webview` 到一个指定的 webContents 的值。当一个 `webview` 第一次载入一个新的 webContent 被创建,这个属性被设置为它的示例 标识。为一个新的或者已存在的 webview 设置这个属性,连接它到当前渲染其中另一个不同的 webview 中已存在的 webContents。
已存在的 webview 将会看到 `destroy` 事件,然后当一个新的 url 被载入将创建一个新的 webContents 。
## 方法
`webview` 标签有以下方法:
**注意:** `webview` 元素必须在使用这些方法之前被加载。
**示例**
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('dom-ready', () => {
webview.openDevTools()
})
```
### `<webview>.loadURL(url[, options])`
* `url` URL
* `options` Object (可选)
* `httpReferrer` String —— 一个 HTTP Referrer url。
* `userAgent` String —— 发起请求的一个用户代理。
* `extraHeaders` String —— 通过 "\n" 分隔的额外的 headers。
在 webview 中加载 `url` , `url` 必须包含协议前缀。例如, `http://` 或 `file://`。
### `<webview>.getURL()`
返回 `String` —— 访客页面的 URL。
### `<webview>.getTitle()`
返回 `String` —— 访客页面的标题。
### `<webview>.isLoading()`
返回 `Boolean` —— 访客页面是否还在加载资源。
### `<webview>.isWaitingForResponse()`
返回 `Boolean` —— 访客页面是否正在等待一个页面上主资源的 first-response。
### `<webview>.stop()`
停止任何正在等待的导航。
### `<webview>.reload()`
重新载入访客页面。
### `<webview>.reloadIgnoringCache()`
重新载入访客页面并忽略缓存。
### `<webview>.canGoBack()`
返回 `Boolean` —— 访客页面是否可以后退。
### `<webview>.canGoForward()`
返回 `Boolean` —— 访客页面是否可以前进。
### `<webview>.canGoToOffset(offset)`
* `offset` Integer
返回 `Boolean` —— 访客页面是否可以跳到 `offset`。
### `<webview>.clearHistory()`
清除导航历史。
### `<webview>.goBack()`
使访客页面后退。
### `<webview>.goForward()`
使访客页面向前。
### `<webview>.goToIndex(index)`
* `index` Integer
导航到指定的绝对索引。
### `<webview>.goToOffset(offset)`
* `offset` Integer
导航到指定的相对于当前页的偏移。
### `<webview>.isCrashed()`
返回 `Boolean` —— 渲染器进程是否崩溃。
### `<webview>.setUserAgent(userAgent)`
* `userAgent` String
重写访客页面的用户代理。
### `<webview>.getUserAgent()`
返回 `String` —— 访客页面的用户代理。
### `<webview>.insertCSS(css)`
* `css` String
注入 CSS 到访客页面。
### `<webview>.executeJavaScript(code, userGesture, callback)`
* `code` String
* `userGesture` Boolean —— 默认为 `false`.
* `callback` Function (可选) —— 脚本被执行后调用。
* `result` Any
在页面中执行 `code` 。如果 `userGesture` 被设置,它将在页面中创建用户的手势上下文。需要用户操作的 HTML APIs 如 `requestFullScreen`, 可以利用这个选项的优势来自动完成。
### `<webview>.openDevTools()`
打开访客页面的 开发者工具窗口。
### `<webview>.closeDevTools()`
关闭访客页面的开发者工具窗口。
### `<webview>.isDevToolsOpened()`
返回 `Boolean` —— 访客页面是否附加了一个开发者工具窗口。
### `<webview>.isDevToolsFocused()`
返回 `Boolean` —— 访客页面的开发者工具窗口是否获得焦点。
### `<webview>.inspectElement(x, y)`
* `x` Integer
* `y` Integer
开始检查在访客页面中 (`x`, `y`) 位置的元素。
### `<webview>.inspectServiceWorker()`
为出现在访客页面中的服务 worker 上下文打开开发者工具。
### `<webview>.setAudioMuted(muted)`
* `muted` Boolean
设置访客页面静音。
### `<webview>.isAudioMuted()`
返回 `Boolean` —— 访客页面是否被静音。
### `<webview>.undo()`
在页面中执行编辑命令 `undo`。
### `<webview>.redo()`
在页面中执行编辑命令 `redo`。
### `<webview>.cut()`
在页面中执行编辑命令 `cut`。
### `<webview>.copy()`
在页面中执行编辑命令 `copy`。
### `<webview>.paste()`
在页面中执行编辑命令 `paste` 。
### `<webview>.pasteAndMatchStyle()`
在页面中执行编辑命令 `pasteAndMatchStyle` 。
### `<webview>.delete()`
在页面中执行编辑命令 `delete`。
### `<webview>.selectAll()`
在页面中执行编辑命令 `selectAll` 。
### `<webview>.unselect()`
在页面中执行编辑命令 `unselect`。
### `<webview>.replace(text)`
* `text` String
在页面中执行编辑命令 `replace`。
### `<webview>.replaceMisspelling(text)`
* `text` String
在页面中执行编辑命令 `replaceMisspelling`。
### `<webview>.insertText(text)`
* `text` String
插入 `text` 到获得焦点的元素。
### `<webview>.findInPage(text[, options])`
* `text` String —— 要搜索的内容,不能为空。
* `options` Object (可选)
* `forward` Boolean —— 是向前或者向后搜索,默认为 `true`。
* `findNext` Boolean —— 操作是第一次请求还是一个跟随的步骤,默认为 `false`。
* `matchCase` Boolean —— 是否大小写敏感,默认为 `false`。
* `wordStart` Boolean —— 是否只查找单词的开头,默认为 `false`。
* `medialCapitalAsWordStart` Boolean —— 当结合使用 `wordStart`时,接受一个匹配在单词的中间,如果匹配是一个大写字符开始后跟小写或者没有其它字母。接受几个其它的词内匹配,默认为 `false`。
开始一个请求在 web 页面中查找所有关于 `text` 的匹配,并返回一个 `Integer` 代表这个请求的请求 id。请求的结果可以被通过订阅 [`found-in-page`](web-view-tag.md#event-found-in-page) 事件来获得。
### `<webview>.stopFindInPage(action)`
* `action` String —— 当 [`<webview>.findInPage`](web-view-tag.md#webviewtagfindinpage) 请求结束之后指定一个动作发生。
* `clearSelection` —— 清空所选。
* `keepSelection` —— 转换选择到一个正常的选择。
* `activateSelection` —— 获得焦点并点击选定节点。
为 `webview` 使用提供的 `action` 停止任何 `findInPage` 请求。
### `<webview>.print([options])`
打印 `webview` 的 web 页面。和 `webContents.print([options])` 相同。
### `<webview>.printToPDF(options, callback)`
打印 `webview` 的 web 页面为 PDF,和 `webContents.printToPDF(options, callback)` 一样。
### `<webview>.capturePage([rect, ]callback)`
捕捉一个 `webview` 的页面截图。和 `webContents.capturePage([rect, ]callback)` 一样。
### `<webview>.send(channel[, arg1][, arg2][, ...])`
* `channel` String
* `arg` (可选)
通过 `channel` 发送一个异步消息到渲染进程,你也可以发送任意参数。渲染进程可以通过使用 `ipcRender` 模块监听 `channel` 事件来处理消息。
查看 [webContents.send](web-contents.md#webcontentssendchannel-args) 中的示例。
### `<webview>.sendInputEvent(event)`
* `event` Object
发送一个输入的 `event` 到页面。
查看 [webContents.sendInputEvent](web-contents.md#webcontentssendinputeventevent)
了解 `event` 对象的详细描述。
### `<webview>.setZoomFactor(factor)`
* `factor` Number —— 缩放系数。
改变缩放系数到指定值。缩放系数通过浮点数表示,如 3.0 = 300%。
### `<webview>.setZoomLevel(level)`
* `level` Number —— Zoom 级别
改变缩放级别到指定值。原始大小是 0 ,每次增加或者减少表示相对默认缩放了 20%,分别限制为原始尺寸的 300% 和 50% 。
### `<webview>.showDefinitionForSelection()` _macOS_
显示在页面上搜索选定单词的弹出字典。
### `<webview>.getWebContents()`
返回 `WebContents` —— 这个 `webview` 相关的 [WebContents](web-contents.md) 。
## DOM 事件
以下 DOM 事件 在 `webview` 标签中可用:
### Event: 'load-commit'
返回:
* `url` String
* `isMainFrame` Boolean
当一个加载完成后触发。 这个包含当前文档的导航和 subframe 文档级的加载,但是不包含异步资源加载。
### Event: 'did-finish-load'
在导航加载完成时触发,也就是 tab 的 spinner 停止 spinning 时,并且 `onload` 事件被发出后。
### Event: 'did-fail-load'
返回:
* `errorCode` Integer
* `errorDescription` String
* `validatedURL` String
* `isMainFrame` Boolean
这个事件和 `did-finish-load` 很像,但是当加载失败或者被取消时触发,即 `window.stop()` 被调用。
### Event: 'did-frame-finish-load'
返回:
* `isMainFrame` Boolean
当一个 frame 完成导航之后触发。
### Event: 'did-start-loading'
对应时间点为当 tab 的 spinner开始 spinning 时。
### Event: 'did-stop-loading'
对应时间点为当 tab 的 spinner 停止 spinning 时。
### Event: 'did-get-response-details'
返回:
* `status` Boolean
* `newURL` String
* `originalURL` String
* `httpResponseCode` Integer
* `requestMethod` String
* `referrer` String
* `headers` Object
* `resourceType` String
当关于一个请求的资源的明细可用时被触发。
`status` 表示 socket 连接下载该资源。
### Event: 'did-get-redirect-request'
返回:
* `oldURL` String
* `newURL` String
* `isMainFrame` Boolean
请求一个资源时当一个重定向被接收到时触发。
### Event: 'dom-ready'
当给定 frame 中的文档被加载后触发。
### Event: 'page-title-updated'
返回:
* `title` String
* `explicitSet` Boolean
当页面标题在导航期间被设置后触发。 `explicitSet` 在标题从文件 URL 合成时为 `false` 。
### Event: 'page-favicon-updated'
返回:
* `favicons` String[] - Array of URLs.
当页面接收到 favicon urls 时被触发。
### Event: 'enter-html-full-screen'
当页面进入被 HTML API 触发的全屏时触发。
### Event: 'leave-html-full-screen'
当页面被 HTML API 触发离开全屏时触发。
### Event: 'console-message'
返回:
* `level` Integer
* `message` String
* `line` Integer
* `sourceId` String
当访客窗口记录了一个 控制台消息时触发。
下面的示例代码转发所有日志消息到嵌入者的控制台,不考虑日志级别或者其它属性。
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('console-message', (e) => {
console.log('Guest page logged a message:', e.message)
})
```
### Event: 'found-in-page'
返回:
* `result` Object
* `requestId` Integer
* `activeMatchOrdinal` Integer —— 激活的匹配的位置。
* `matches` Integer —— 匹配的数量。
* `selectionArea` Object —— 第一个匹配区域的坐标。
当 [`webview.findInPage`](web-view-tag.md#webviewtagfindinpage) 请求的一个结果可用时触发。
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('found-in-page', (e) => {
webview.stopFindInPage('keepSelection')
})
const requestId = webview.findInPage('test')
console.log(requestId)
```
### Event: 'new-window'
返回:
* `url` String
* `frameName` String
* `disposition` String —— 可能是 `default`, `foreground-tab`, `background-tab`, `new-window`, `save-to-disk` 和`other`。
* `options` Object —— 被用来创建新的 `BrowserWindow` 的选项。
当访客页面试图打开一个新的浏览器窗口时触发。
如下示例代码使用系统默认的浏览器打开新的 url 。
```javascript
const {shell} = require('electron')
const webview = document.getElementById('foo')
webview.addEventListener('new-window', (e) => {
const protocol = require('url').parse(e.url).protocol
if (protocol === 'http:' || protocol === 'https:') {
shell.openExternal(e.url)
}
})
```
### Event: 'will-navigate'
返回:
* `url` String
当一个用户或者页面想要开始导航时发射。当 `window.location` 对象被改变或者用户点击了页面中一个链接时都可能发生。
这个事件在使用 如 `<webview>.loadURL` 和 `<webview>.back` APIs 以编程方式开始导航的时候不会触发。
在页面内的导航也不会被触发,比如点击锚点链接,或者更新 `window.location.hash`。应该使用 `did-navigate-in-page` 事件处理这个目的。
调用 `event.preventDefault()` 不会有任何效果。
### Event: 'did-navigate'
返回:
* `url` String
当一个导航做出时被触发。
这个事件对于页面内的导航不会被发射,比如点击锚点或者更新 `window.location.hash`。应该使用 `did-navigate-in-page` 事件处理这个目的。
### Event: 'did-navigate-in-page'
返回:
* `isMainFrame` Boolean
* `url` String
当一个页面内导航发生时触发。
当页面内的导航发生,页面的 URL 改变但是不会导航出这个页面。例如当锚点链接被点击,或者 DOM 的 `hashchange` 事件被触发。
### Event: 'close'
当访客页面试图关闭它自己时触发。
以下示例代码在访客试图关闭它自身时导航 `webview` 到 `about:blank`。
```javascript
const webview = document.getElementById('foo')
webview.addEventListener('close', () => {
webview.src = 'about:blank'
})
```
### Event: 'ipc-message'
返回:
* `channel` String
* `args` Array
当访客页面已经发送一个异步消息给嵌入者页面时触发。
使用 `sendToHost` 方法和 `ipc-message` 事件,你可以简单的在访客页面和嵌入者页面之间通讯:
```javascript
// In embedder page.
const webview = document.getElementById('foo')
webview.addEventListener('ipc-message', (event) => {
console.log(event.channel)
// Prints "pong"
})
webview.send('ping')
```
```javascript
// In guest page.
const {ipcRenderer} = require('electron')
ipcRenderer.on('ping', () => {
ipcRenderer.sendToHost('pong')
})
```
### Event: 'crashed'
当渲染进程崩溃时触发。
### Event: 'gpu-crashed'
当 gpu 进程崩溃时触发。
### Event: 'plugin-crashed'
返回:
* `name` String
* `version` String
当一个插件进程崩溃时触发。
### Event: 'destroyed'
当 WebContents 被销毁时触发。
### Event: 'media-started-playing'
当媒体开始播放时触发。
### Event: 'media-paused'
当媒体暂停或者继续播放时触发。
### Event: 'did-change-theme-color'
返回:
* `themeColor` String
当一个页面的主题颜色改变时触发。这通常通过遇到一个 meta 标签:
```html
<meta name='theme-color' content='#ff0000'>
```
### Event: 'update-target-url'
返回:
* `url` String
当鼠标移动到一个链接或者键盘移动焦点到一个链接时触发。
### Event: 'devtools-opened'
当开发者工具被打开时触发。
### Event: 'devtools-closed'
当开发者工具被关闭时触发。
### Event: 'devtools-focused'
当开发者工具打开/获得焦点时触发。
参考:[blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
- 索引
- 前言.关于Electron
- 第一部分 开发指南
- 第1章.平台支持
- 第2章.安全、原生功能和你的责任
- 第3章.版本说明
- 第4章.发行应用
- 第5章.Mac App商店提交指南
- 第6章.Windows商店指南
- 第7章.应用打包
- 第8章.使用Node原生模块
- 第9章.调试主进程
- 9.1.在VSCode中调试
- 9.2.在node-inspector中调试
- 第10章.使用Selenium和WebDriver
- 第11章.DevTools扩展
- 第12章.使用Pepper Flash插件
- 第13章.使用Widevine CDM插件
- 第14章.通过自动化持续集成系统进行测试
- 第15章.离屏渲染
- 第二部分 使用教程
- 第16章.快速入门
- 第17章.桌面环境集成
- 第18章.在线/离线事件探测
- 第19章.应答式编译器(REPL)
- 第三部分 API参考
- 第20章.API简介
- 第21章.进程对象
- 第22章.Chrome的命令行开关
- 第23章.环境变量
- 第24章.定制的DOM元素
- 24.1.File 对象
- 24.2.webview 标签
- 第25章.主进程模块
- 25.1.app
- 25.2.BrowserWindow
- 25.3.无框架窗口
- 第26章.渲染进程模块
- 第27章.两种进程可用的模块
- 第四部分 高级主题
- 附 FAQ
- 附 文档规范
- 附 示例用例
- 1.无边框窗口