# 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.無邊框窗口