[TOC]
## Web Workders
Web Worker為Web內容在后臺線程中運行腳本提供了一種簡單的方法。線程可以執行任務而不干擾用戶界面。此外,他們可以使用XMLHttpRequest執行 I/O \(盡管responseXML和通道屬性總是為空\)。一旦創建, 一個worker 可以將消息發送到創建它的JavaScript代碼, 通過將消息發布到該代碼指定的事件處理程序 \(反之亦然\)。
### API
一個worker是使用一個構造函數創建的一個對象\(e.g.[`Worker()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker/Worker)\) 運行一個命名的JavaScript文件 - 這個文件包含將在工作線程中運行的代碼; workers 運行在另一個全局上下文中,不同于當前的[`window`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window)。 因此,使用[`window`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window)快捷方式獲取當前全局的范圍 \(而不是[`self`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/self)\) 在一個[`Worker`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker)內將返回錯誤。
在專用workers的情況下,[`DedicatedWorkerGlobalScope`](https://developer.mozilla.org/zh-CN/docs/Web/API/DedicatedWorkerGlobalScope)對象代表了worker的上下文(專用workers是指標準worker僅在單一腳本中被使用;共享worker的上下文是[`SharedWorkerGlobalScope`](https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorkerGlobalScope)對象)。一個專用worker僅僅能被首次生成它的腳本使用,而共享worker可以同時被多個腳本使用。
> 參照 [The Web Workers API landing page](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)獲取workers的參考文檔和更多指引。
在worker線程中你可以運行任何你喜歡的代碼,不過有一些例外情況。比如:在worker內直接操作DOM節點,或者使用[`window`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window)對象的默認方法和屬性。然而你可以使用大量window對象之下的東西,包括WebSockets,IndexedDB以及FireFox OS專用的Data Store API等數據存儲機制。查看[Functions and classes available to workers](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Functions_and_classes_available_to_workers)獲取詳情。
workers和主線程間的數據傳遞通過這樣的消息機制進行——雙方都使用postMessage\(\)方法發送各自的消息,使用onmessage事件處理函數來響應消息(消息被包含在[`Message`](https://developer.mozilla.org/zh-CN/docs/Web/Reference/Events/Message)事件的data屬性中)。這個過程中數據并不是被共享而是被復制。
只要運行在同源的父頁面中,workers可以依次生成新的workers;并且可以使用[`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) 進行網絡I/O,responseXML和XMLHttpRequest的通道屬性一直返回null的情況除外。
### Worker 的使用場景
* 執行一些大計算量的操作
* 異步加載資源
### **適用于 Worker 的功能**
由于 Web Worker 的多線程行為,所以它們只能使用 JavaScript 功能的子集:
* navigator 對象
* location 對象(只讀)
* XMLHttpRequest
* setTimeout\(\)/clearTimeout\(\) 和 setInterval\(\)/clearInterval\(\)
* 應用緩存
* 使用 importScripts\(\) 方法導入外部腳本
* 生成其他 Web Worker
Worker 無法使用:
* DOM(非線程安全)
* window 對象
* document 對象
* parent 對象
### 專用Workder
#### worker特性檢測
```
//main.js
if (window.Worker) {
...
}
```
#### 生成一個專用worker
調用[`Worker()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker/Worker)的構造器,指定一個腳本的URI來執行worker線程(main.js):
```
//main.js
var myWorker = new Worker('worker.js');
```
#### 專用worker中消息的接收和發送
向一個worker發送消息:
```
//main.js
first.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
second.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
```
變量first和second代表2個`<input>`元素;它們當中任意一個的值發生改變時,myWorker.postMessage\(\[first.value,second.value\]\)會將這2個值組成數組發送給worker。
在worker中接收到消息后,我們可以寫這樣一個事件處理函數代碼作為響應:
```
//worker.js
onmessage = function(e) {
console.log('Message received from main script');
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
console.log('Posting message back to main script');
postMessage(workerResult);
}
```
onmessage處理函數允許我們在任何時刻,一旦接收到消息就可以執行一些代碼,代碼中消息本身作為事件的data屬性進行使用。這里我們簡單的對這2個數字作乘法處理并再次使用postMessage\(\)方法,將結果回傳給主線程。
回到主線程,我們再次使用onmessage以響應worker回傳的消息:
```
myWorker.onmessage = function(e) {
result.textContent = e.data;
console.log('Message received from worker');
}
```
> 作為參數傳遞給worker構造器的URI必須遵循[同源策略](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)。
>
> 在主線程中使用時,`onmessage`和`postMessage()`必須掛在worker對象上,而在worker中使用時不用這樣做。原因是,在worker內部,worker是有效的全局作用域。
>
> 當一個消息在主線程和worker之間傳遞時,它被復制或者轉移了,而不是共享。
#### 終止worker {#終止worker}
如果你需要從主線程中立刻終止一個運行中的worker,可以調用worker的[`terminate`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker)方法:
```
myWorker.terminate();
```
worker 線程會被立即殺死,不會有任何機會讓它完成自己的操作或清理工作。
而在worker線程中,workers 也可以調用自己的 [`close`](https://developer.mozilla.org/zh-CN/docs/Web/API/WorkerGlobalScope) 方法進行關閉:
```
close();
```
#### 處理錯誤
當 worker 出現運行中錯誤時,它的 `onerror` 事件處理函數會被調用。它會收到一個擴展了 `ErrorEvent` 接口的名為`error`的事件。
該事件不會冒泡并且可以被取消;為了防止觸發默認動作,worker 可以調用錯誤事件的 [`preventDefault()`](https://developer.mozilla.org/en/DOM/event.preventDefault)`方法。`
錯誤事件有以下三個用戶關心的字段:
`message`可讀性良好的錯誤消息。
`filename`發生錯誤的腳本文件名。
`lineno`發生錯誤時所在腳本文件的行號。
#### 生成subworker
如果需要的話 worker 能夠生成更多的 worker。這就是所謂的subworker,它們必須托管在同源的父頁面內。而且,subworker 解析 URI 時會相對于父 worker 的地址而不是自身頁面的地址。這使得 worker 更容易記錄它們之間的依賴關系。
#### 引入腳本與庫
Worker 線程能夠訪問一個全局函數`importScripts()`來引入腳本,該函數接受0個或者多個URI作為參數來引入資源;以下例子都是合法的:
```
importScripts(); /* 什么都不引入 */
importScripts('foo.js'); /* 只引入 "foo.js" */
importScripts('foo.js', 'bar.js'); /* 引入兩個腳本 */
```
瀏覽器加載并運行每一個列出的腳本。每個腳本中的全局對象都能夠被 worker 使用。如果腳本無法加載,將拋出 `NETWORK_ERROR` 異常,接下來的代碼也無法執行。而之前執行的代碼\(包括使用[`window.setTimeout()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setTimeout)異步執行的代碼\)依然能夠運行。`importScripts()`**之后**的函數聲明依然會被保留,因為它們始終會在其他代碼之前運行。
> 腳本的下載順序不固定,但執行時會按照傳入 `importScripts()`中的文件名順序進行。這個過程是同步完成的;直到所有腳本都下載并運行完畢, `importScripts()`才會返回。
### 共享worker
一個共享worker可以被多個腳本使用——即使這些腳本正在被不同的window、iframe或者worker訪問。這一部分,我們會討論[共享worker基礎示例](https://github.com/mdn/simple-shared-worker)([運行共享worker](https://mdn.github.io/simple-shared-worker/))中的javascript代碼:該示例與專用worker基礎示例非常相像,只是有2個可用函數被存放在不同腳本文件中:兩數相乘函數,以及求平方函數。這兩個腳本用同一個worker來完成實際需要的運算。
#### 生成一個共享worker
```
var myWorker = new SharedWorker('worker.js');
```
專用worker與共享worker一個非常大的區別在于,與一個共享worker通信必須通過端口對象——一個確切的打開的端口供腳本與worker通信(在專用worker中這一部分是隱式進行的)。
在傳遞消息之前,端口連接必須被顯式的打開,打開方式是使用onmessage事件處理函數或者start\(\)方法。盡管示例中的 [multiply.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js) 和 [worker.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/worker.js) 文件調用了start\(\)方法,這些調用并不那么重要因為onmessage事件處理函數正在被使用。start\(\)方法的調用只在一種情況下需要,那就是消息事件被addEventListener\(\)方法使用。
在傳遞消息之前,端口連接必須被顯式的打開,打開方式是使用onmessage事件處理函數或者start\(\)方法。盡管示例中的 [multiply.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js) 和 [worker.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/worker.js) 文件調用了start\(\)方法,這些調用并不那么重要因為onmessage事件處理函數正在被使用。start\(\)方法的調用只在一種情況下需要,那就是消息事件被addEventListener\(\)方法使用。
在使用start\(\)方法打開端口連接時,如果父級線程和worker線程需要雙向通信,那么它們都需要調用start\(\)方法。
```
myWorker.port.start(); // 父級線程中的調用
```
```
port.start(); // worker線程中的調用, 假設port變量代表一個端口
```
## History
### 穿越歷史
使用back(),forward()和go()方法完成用戶歷史記錄的前后移動。
### 前進和后退
要回溯歷史,只要做到:
```
window.history.back();
```
這與用戶點擊瀏覽器工具欄上的“后退”按鈕完全相同。
同樣,你可以向前移動(就像用戶點擊了Forward按鈕),如下所示:
```
window.history.forward();
```
### 轉向歷史上的特定時刻
您可以使用go()方法從會話歷史記錄中加載特定的頁面,通過它相對于當前頁面的位置來標識(當前頁面當然是相對索引0)。
向后移動一頁(相當于回調()):
```
window.history.go(-1);
```
向前移動頁面,就像調用forward()一樣:
```
window.history.go(1);
```
同樣,您可以通過傳遞2來前進2頁,依此類推。
您可以通過查看length屬性的值來確定歷史堆棧中的頁數:
```
var numberOfEntries = window.history.length;
```
> Internet Explorer支持將字符串URL作為參數傳遞給();這是非標準的,不被Gecko支持。
### 添加和修改歷史條目
HTML5引入了history.pushState()和history.replaceState()方法,可以分別添加和修改歷史條目。這些方法與window.onpopstate事件一起工作。
使用history.pushState()更改在更改狀態后創建的XMLHttpRequest對象的HTTP標頭中使用的引用鏈接。引用者將是在創建XMLHttpRequest對象時窗口是這個文檔的URL。
#### pushState()方法的例子
假設[http://mozilla.org/foo.html執行以下JavaScript:](http://mozilla.org/foo.html執行以下JavaScript:)
`var stateObj = {foo:“bar”};`
`history.pushState(stateObj,“page 2”,“bar.html”);`
這將導致URL欄顯示[http://mozilla.org/bar.html,但不會導致瀏覽器加載bar.html甚至檢查bar.html是否存在。](http://mozilla.org/bar.html,但不會導致瀏覽器加載bar.html甚至檢查bar.html是否存在。)
現在假設用戶現在導航到[http://google.com,然后點擊返回。此時,URL欄會顯示http://mozilla.org/bar.html,頁面將會得到一個狀態對象包含stateObj副本的popstate事件。頁面本身看起來像foo.html,雖然頁面可能會在popstate事件中修改它的內容。](http://google.com,然后點擊返回。此時,URL欄會顯示http://mozilla.org/bar.html,頁面將會得到一個狀態對象包含stateObj副本的popstate事件。頁面本身看起來像foo.html,雖然頁面可能會在popstate事件中修改它的內容。)
如果我們再次點擊,URL將變為[http://mozilla.org/foo.html,文檔將會得到另一個popstate事件,這次是一個null狀態對象。在這里,返回不會改變文檔內容與上一步的內容,盡管文檔可能會在接收到popstate事件后手動更新其內容。](http://mozilla.org/foo.html,文檔將會得到另一個popstate事件,這次是一個null狀態對象。在這里,返回不會改變文檔內容與上一步的內容,盡管文檔可能會在接收到popstate事件后手動更新其內容。)
pushState()方法
pushState()有三個參數:一個狀態對象,一個標題(當前被忽略)和(可選)一個URL。讓我們來更詳細地檢查這三個參數中的每一個:
* 狀態對象 - 狀態對象是與由pushState()創建的新歷史記錄條目相關聯的JavaScript對象。每當用戶導航到新狀態時,將觸發一個popstate事件,并且該事件的state屬性包含歷史記錄條目狀態對象的副本。
狀態對象可以是任何可以序列化的東西。由于Firefox會將狀態對象保存到用戶的磁盤中,以便在用戶重新啟動瀏覽器之后可以恢復它們,所以我們在狀態對象的序列化表示上強加了一個640k字符的大小限制。如果你傳遞了一個狀態對象的序列化表示大于這個pushState(),該方法將拋出一個異常。如果您需要更多的空間,建議您使用sessionStorage和/或localStorage。
* 標題 - Firefox目前忽略這個參數,雖然它可能在將來使用它。在這里傳遞空字符串應該對將來對方法的更改是安全的。或者,您可以傳遞您正在移動的狀態的簡短標題。
* URL - 新的歷史記錄的URL由此參數給出。請注意,在調用pushState()之后,瀏覽器將不會嘗試加載此URL,但可能會在稍后嘗試加載URL,例如在用戶重新啟動瀏覽器之后。新的URL不需要是絕對的;如果它是相對的,則相對于當前URL解析。新的網址必須與當前網址的來源相同;否則,pushState()會拋出異常。該參數是可選的;如果未指定,則將其設置為文檔的當前URL。
從某種意義上說,調用pushState()類似于設置window.location =“\#foo”,因為兩者都將創建并激活與當前文檔相關聯的另一個歷史記錄條目。但是pushState()有一些優點:
* 新的URL可以是與當前URL相同的任何URL。相比之下,只有修改hash值時,設置window.location才能使您保持在同一個文檔中。
* 如果您不想更改網址,則不必更改網址。相反,設置window.location =“\#foo”;如果當前hash不是\#foo,則只創建一個新的歷史記錄條目。
* 您可以將任意數據與新的歷史記錄條目相關聯。使用基于hash的方法,您需要將所有相關數據編碼成一個簡短的字符串。
* 如果標題隨后被瀏覽器使用,則可以使用該數據(獨立于hash)。
> pushState()永遠不會引發hashchange事件,即使新的URL僅在其哈希中與舊的URL不同。
#### replaceState()方法
history.replaceState()的運行方式與history.pushState()完全相同,只是replaceState()修改了當前的歷史記錄,而不是創建一個新的歷史記錄。請注意,這并不妨礙在全局瀏覽器歷史記錄中創建新條目。
當您想要更新當前歷史記錄條目的狀態對象或URL以響應某些用戶操作時,replaceState()特別有用。
## ContentEditable
只要將HTML元素的[`contenteditable`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes#attr-contenteditable)屬性值設置`true`, 就可以激活編輯模式,那么該元素范圍中的內容都是可編輯的.
```
<div contenteditable="true">
This text can be edited by the user.
</div>
```
## 拖放
## 焦點管理
在 HTML5 工作草案中,DOM 屬性
[`activeElement`](https://developer.mozilla.org/cn/DOM/document.activeElement)與方法 [`hasFocus()`](https://developer.mozilla.org/cn/DOM/document.hasFocus)為程序員提供了更好的控制頁面交互的能力,特別是對于用戶行為引發的交互。例如,它們都可以用于統計使用目的,跟蹤頁面特定鏈接的點擊次數,計算元素獲得焦點的次數等等。此外,當與 AJAX 技術結合以后,將會減少向服務器請求的數目,這取決于用戶的活躍程度和頁面的布局。
### document.hasFocus
`Document.hasFocus()`方法返回一個[`Boolean`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Boolean),表明當前文檔或者當前文檔內的節點是否獲得了焦點。該方法可以用來判斷當前文檔中的活動元素是否獲得了焦點。
> 當查看一個文檔時,當前文檔中獲得焦點的元素一定是當前文檔的活動元素,但一個文檔中的活動元素不一定獲得了焦點.。例如, 一個在后臺的窗口中的活動元素一定沒有獲得焦點。
#### 語法
```
focused = document.hasFocus();
```
**返回值**
如果當前文檔的活動元素獲得了焦點,返回`true`,否則返回false。
## Web-based protocol handlers
### 背景
利用非http協議,從網頁鏈接到一些別的資源,這種做法是相當普遍的。比如 `mailto:` 協議:
```
<a href="mailto:webmaster@example.com">Web Master</a>
```
當Web頁面作者想直接從網頁上,為用戶提供一個方便的方式發送一個電子郵件,時可以使用mailto:鏈接。激活鏈接時,瀏覽器應該啟動默認的桌面應用程序來處理電子郵件。你可以認為這是一個_基于桌面的_協議處理器。
基于網絡的協議處理程序也允許基于web的應用程序參與這一過程。隨著越來越多的類型的應用程序遷移到web,這變得越來越重要。事實上,有許多基于web的電子郵件處理的應用程序可以處理一個mailto鏈接。
### 注冊
設置一個web應用程序作為一個協議處理器不是一個很麻煩的過程。web應用程序可以使用[registerProtocolHandler\(\)](https://developer.mozilla.org/en-US/docs/Web/API/navigator.registerProtocolHandler)注冊到瀏覽器上,從而對于一個給定的協議來講,作為一個潛在的處理程序。例如:
```
navigator.registerProtocolHandler("mailto",
"https://www.example.com/?uri=%s",
"Example Mail");
```
參數為:
* 協議名稱.
* url模板。%s用來替換鏈接的`href`屬性,之后通過這個url來發起一個GET請求.
* 一個對用戶友好的協議處理器的名字.
> 試圖執行登記或注冊時,當前網頁必須與提供的URL模板在相同的域,否則將會失敗。例如,[http://example.com/homepage.html可以為\`http://example.com/handle\_mailto/%s\`注冊一個協議處理程序](http://example.com/homepage.html可以為`http://example.com/handle_mailto/%s`注冊一個協議處理程序), 但`http://example.org/handle_mailto/%s不可以`.
多次注冊相同的協議處理程序會彈出不同的通知,表明協議處理器已經注冊。因此,發起一個注冊協議處理程序的請求,之后檢查是否注冊是一個很好的方法。比如下面的例子。
#### 例子
```
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>Web Protocol Handler Sample - Register</title>
<script type="text/javascript">
var url = "http://starkravingfinkle.org/projects/wph/handler.php?value=%s";
if (!navigator.isProtocolHandlerRegistered("fake", url)) {
navigator.registerProtocolHandler("fake", url, "Fake Protocol");
}
</script>
</head>
<body>
<h1>Web Protocol Handler Sample</h1>
<p>This web page will install a web protocol handler for the <code>fake:</code> protocol.</p>
</body>
</html>
```
### 激活
現在,只要用戶點擊鏈接,使用注冊協議,瀏覽器將跳轉到web應用程序注冊時提供的URL。Firefox在默認情況下,跳轉前會提示用戶操作。

#### Example
```
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>Web Protocol Handler Sample - Test</title>
</head>
<body>
<p>Hey have you seen <a href="fake:this%20is%20fake">this</a> before?</p>
</body>
</html>
```
### 處理
下一步是處理這個動作。瀏覽器在激活的鏈接中提取出href屬性,之后與注冊時提供的URL模板進行拼裝,之后經由拼裝好的URL發起一個HTTP GET請求.因此下面的例子中,瀏覽器會基于此URL發起一個GET請求:
```
http://starkravingfinkle.org/projects/wph/handler.php?value=fake:this%20is%20fake
```
服務端代碼可以提取查詢字符串的參數,執行所需的操作。
> 服務端代碼會接收到href的**全部**內容。這意味著服務端代碼必須解析出數據中的協議。
## window.requestAnimationFrame
`window.requestAnimationFrame()`
方法告訴瀏覽器您希望執行動畫并請求瀏覽器調用指定的函數在下一次重繪之前更新動畫。該方法使用一個回調函數作為參數,這個回調函數會在瀏覽器重繪之前調用。
**注意:**
若您想要在下次重繪時產生另一個動畫畫面,您的回調例程必須調用`requestAnimationFrame()`。
當你準備好更新屏幕畫面時你就應用此方法。這會要求你的動畫函數在瀏覽器下次重繪前執行。回調的次數常是每秒60次,但大多數瀏覽器通常匹配 W3C 所建議的刷新率。如果網頁于后臺或隱藏在[`<iframe>`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe)里面,重繪頻率可能會大大降低以提升性能和電池耐久度。
回調函數只會被傳入一個參數,[`DOMHighResTimeStamp`](https://developer.mozilla.org/zh-CN/docs/Web/API/DOMHighResTimeStamp),指示當前被 requestAnimationFrame 序列化的函數隊列被觸發的時間。即使經過了許多對之前回調的計算工作時間,單個幀中的多個回調也都將被傳入相同的時間戳。此數值是一個十進制數,單位毫秒,最小精度為1ms\(1000μs\)。
### 語法
```
window.requestAnimationFrame(callback);
```
#### 參數
`callback`
一個在每次需要重新繪制動畫時調用的包含指定函數的參數。這個回調函數有一個傳參,[`DOMHighResTimeStamp`](https://developer.mozilla.org/zh-CN/docs/Web/API/DOMHighResTimeStamp),指示從觸發 requestAnimationFrame 回調到現在的時間(從[`performance.now()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Performance/now)取得)。
#### 返回值
一個`long`整數,請求 ID ,也是回調列表中唯一的標識。這是一個非零值,但你恐怕也不能從其值中作出什么臆想。你可以傳此值到[`window.cancelAnimationFrame()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/cancelAnimationFrame)以取消回調函數。
### 范例
```
var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress / 10, 200) + 'px';
if (progress < 2000) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
```
## Fullscreen API
全屏API為使用用戶的整個屏幕呈現網頁內容提供了一個簡單的方法。 API可讓您輕松地指導瀏覽器創建一個元素及其子元素(如果有的話)占據全屏,從而在屏幕上消除所有瀏覽器用戶界面和其他應用程序。
> 目前并不是所有的瀏覽器都使用API的前綴版本。 請查閱總結前綴和名稱差異的表格
### 激活全屏模式
給定一個你想以全屏模式呈現的元素(例如<video>),你可以通過調用它的Element.requestFullscreen()方法以全屏模式呈現它。
### 表現差異
Gecko和WebKit實現之間有一個關鍵的區別:Gecko自動將CSS規則添加到元素,擴展它以填充屏幕:“width:100%; height:100%”。 WebKit不會這樣做; 相反,它將全屏幕元素以相同的大小居中在黑色的屏幕中。 要在WebKit中獲得相同的全屏行為,您需要添加自己的“寬度:100%;高度:100%”。 CSS自己對元素進行規則:
```
#myvideo:-webkit-full-screen {
width: 100%;
height: 100%;
}
```
另一方面,如果您試圖模擬WebKit在Gecko上的行為,則需要將要呈現的元素放置在另一個元素內,而不是使用全屏模式,并使用CSS規則調整內部元素以匹配 你想要的外觀。
### 注意
全屏模式成功使用時,包含該元素的文檔將收到fullscreenchange事件。 當全屏模式退出時,文檔再次收到fullscreenchange事件。 請注意,fullscreenchange事件本身不提供有關文檔是進入還是退出全屏模式的任何信息,但是如果文檔具有非空的fullscreenElement,則說明您處于全屏模式。
### 全屏請求失敗時
不能保證你能夠切換到全屏模式。 例如,<iframe>元素具有allowfullscreen屬性,以便選擇允許其內容以全屏模式顯示。 另外,某些類型的內容(如窗口化插件)無法以全屏模式顯示。 試圖放置一個無法以全屏模式顯示的元素(或者這樣的元素的父代或后代)將不起作用。 相反,請求全屏的元素將收到mozfullscreenerror事件。 當全屏請求失敗時,Firefox會將錯誤消息記錄到Web控制臺,以解釋請求失敗的原因。 但是在Chrome和更新版本的Opera中,不會產生這樣的警告。
> ### 全屏請求需要在事件處理程序中調用,否則將被拒絕。
### 退出全屏模式
您可以通過調用Document.exitFullscreen()方法來退出全屏模式。
### 其他信息
document提供了一些在開發全屏Web應用程序時可能有用的附加信息:
[`fullscreenElement`](https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenElement)
> 當前全屏顯示的元素。 如果不是null,則文檔處于全屏模式。 如果為空,則文檔不處于全屏模式。
[`fullscreenEnabled`](https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenEnabled)
> 文檔當前是否處于允許請求全屏模式的狀態。
### 你的用戶想知道的事情
您需要確保讓用戶知道他們可以按ESC鍵(或F11)退出全屏模式。
此外,在全屏模式下,導航到另一個頁面,更改標簽或切換到其他應用程序(例如,使用Alt-Tab)也會退出全屏模式。
### 例子
```
document.addEventListener("keydown", function(e) {
if (e.keyCode == 13) {
toggleFullScreen();
}
}, false);
function toggleFullScreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
}
```
### 前綴
目前并不是所有的瀏覽器都實現了API的前綴版本(對于廠商不可知的訪問Fullscreen API,你可以使用Fscreen)。 下面是總結前綴和名稱差異的表格:
| Standard | Blink \(Chrome & Opera\)、Edge | Gecko \(Firefox\) | Internet Explorer11 |
| :--- | :--- | :--- | :--- |
| Document.fullscreen | webkitIsFullScreen | mozFullScreen | - |
| Document.fullscreenEnabled | webkitFullscreenEnabled | mozFullScreenEnabled | msFullscreenEnabled |
| Document.fullscreenElement | webkitFullscreenElement | mozFullScreenElement | msFullscreenElement |
| Document.onfullscreenchange | onwebkitfullscreenchange | onmozfullscreenchange | MSFullscreenChange |
| Document.onfullscreenerror | onwebkitfullscreenerror | onmozfullscreenerror | MSFullscreenError |
| Document.exitFullscreen\(\) | webkitExitFullscreen\(\) | mozCancelFullScreen\(\) | msExitFullscreen\(\) |
| Element.requestFullscreen\(\) | webkitRequestFullscreen\(\) | mozRequestFullScreen\(\) | msRequestFullscreen\(\) |
## 在線和離線事件
為了構建一個支持離線的 web 應用,你需要知道你的應用何時真正處于離線狀態。同時,你還需要知道應用何時重新回到了「在線」狀態。實際上,我們可以把需求分解成如下內容:
1. 你需要知道用戶何時回到在線狀態,這樣你就可以與服務器重新同步。
2. 你需要知道用戶何時處于離線狀態,這樣你就可以將對服務器的請求放入隊列中以便稍后使用。
這便是在線/離線事件所要處理的過程。
### API
#### `navigator.onLine`
[`navigator.onLine`](https://developer.mozilla.org/en/DOM/window.navigator.onLine) 是一個值為 `true`/`false` \(`true` 表示在線, `false` 表示離線\) 的屬性。當用戶通過選擇對應的菜單項 \(Firefox 中為 文件 -> 離線工作\) 切換到「離線模式」時,這個值就會被更新。
此外,當瀏覽器長時間無法連接到網絡時,該值也會被更新。根據如下規范:
> `由于用戶點擊一個鏈接或是腳本請求一個遠程頁面(或者類似的操作失敗了)從而導致戶代理無法訪問網絡時, navigator.onLine`
> 屬性返回 false ...
在 Firefox 2 中,當在瀏覽器的離線模式中來回切換時會更新該屬性。 Windows, Linux, 和 OS X 上的 Firefox 41 會在操作系統報告網絡連接變化時更新該屬性。
該屬性存在于舊版本的 Firefox 與 Internet Explorer \(規范就是以這些舊有實現為基礎\),因此你現在就可以使用該屬性。Firefox 2實現了網絡狀態自動檢測。
**`「online」與「offline」` 事件**
Firefox 3 引入了兩個新事件:「`online」與「offline」。當瀏覽器從在線與離線狀態中切換時,這兩個事件會在頁面的<body>` 上觸發。此外,該事件會從 `document.body 冒泡到document 上,最后到達window。兩個事件都無法被取消`\(你無法阻止用戶進入在線或離線狀態\)。
你可以使用幾種熟悉的方式來注冊事件:
* 在 `window,document,或document.body 上使用`[`addEventListener`](https://developer.mozilla.org/en/DOM/element.addEventListener)
* 將 `document`或 `document.body 的.ononline`或 `.onoffline`屬性設置為一個 JavaScript`Function`對象。\(**注意:**由于兼容性原因,不能使用 `window.ononline`或 `window.onoffline`。\)
* 在 HTML 標記中的 `<body>標簽上指定ononline="..."` 或 `onoffline="..."`特性。
#### 示例
```
window.addEventListener('load', function() {
var status = document.getElementById("status");
var log = document.getElementById("log");
function updateOnlineStatus(event) {
var condition = navigator.onLine ? "online" : "offline";
status.className = condition;
status.innerHTML = condition.toUpperCase();
log.insertAdjacentHTML("beforeend", "Event: " + event.type + "; Status: " + condition);
}
window.addEventListener('online', updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);
});
```
#### 注意
如果瀏覽器沒有實現該 API,你可以使用其他方式來檢測是否離線,包括 [AppCache 錯誤事件](http://www.html5rocks.com/en/mobile/workingoffthegrid.html#toc-appcache) 和 [XMLHttpRequest 的響應](http://www.html5rocks.com/en/mobile/workingoffthegrid.html#toc-xml-http-request)。
- 第一部分 HTML
- meta
- meta標簽
- HTML5
- 2.1 語義
- 2.2 通信
- 2.3 離線&存儲
- 2.4 多媒體
- 2.5 3D,圖像&效果
- 2.6 性能&集成
- 2.7 設備訪問
- SEO
- Canvas
- 壓縮圖片
- 制作圓角矩形
- 全局屬性
- 第二部分 CSS
- CSS原理
- 層疊上下文(stacking context)
- 外邊距合并
- 塊狀格式化上下文(BFC)
- 盒模型
- important
- 樣式繼承
- 層疊
- 屬性值處理流程
- 分辨率
- 視口
- CSS API
- grid(未完成)
- flex
- 選擇器
- 3D
- Matrix
- AT規則
- line-height 和 vertical-align
- CSS技術
- 居中
- 響應式布局
- 兼容性
- 移動端適配方案
- CSS應用
- CSS Modules(未完成)
- 分層
- 面向對象CSS(未完成)
- 布局
- 三列布局
- 單列等寬,其他多列自適應均勻
- 多列等高
- 圣杯布局
- 雙飛翼布局
- 瀑布流
- 1px問題
- 適配iPhoneX
- 橫屏適配
- 圖片模糊問題
- stylelint
- 第三部分 JavaScript
- JavaScript原理
- 內存空間
- 作用域
- 執行上下文棧
- 變量對象
- 作用域鏈
- this
- 類型轉換
- 閉包(未完成)
- 原型、面向對象
- class和extend
- 繼承
- new
- DOM
- Event Loop
- 垃圾回收機制
- 內存泄漏
- 數值存儲
- 連等賦值
- 基本類型
- 堆棧溢出
- JavaScriptAPI
- document.referrer
- Promise(未完成)
- Object.create
- 遍歷對象屬性
- 寬度、高度
- performance
- 位運算
- tostring( ) 與 valueOf( )方法
- JavaScript技術
- 錯誤
- 異常處理
- 存儲
- Cookie與Session
- ES6(未完成)
- Babel轉碼
- let和const命令
- 變量的解構賦值
- 字符串的擴展
- 正則的擴展
- 數值的擴展
- 數組的擴展
- 函數的擴展
- 對象的擴展
- Symbol
- Set 和 Map 數據結構
- proxy
- Reflect
- module
- AJAX
- ES5
- 嚴格模式
- JSON
- 數組方法
- 對象方法
- 函數方法
- 服務端推送(未完成)
- JavaScript應用
- 復雜判斷
- 3D 全景圖
- 重載
- 上傳(未完成)
- 上傳方式
- 文件格式
- 渲染大量數據
- 圖片裁剪
- 斐波那契數列
- 編碼
- 數組去重
- 淺拷貝、深拷貝
- instanceof
- 模擬 new
- 防抖
- 節流
- 數組扁平化
- sleep函數
- 模擬bind
- 柯里化
- 零碎知識點
- 第四部分 進階
- 計算機原理
- 數據結構(未完成)
- 算法(未完成)
- 排序算法
- 冒泡排序
- 選擇排序
- 插入排序
- 快速排序
- 搜索算法
- 動態規劃
- 二叉樹
- 瀏覽器
- 瀏覽器結構
- 瀏覽器工作原理
- HTML解析
- CSS解析
- 渲染樹構建
- 布局(Layout)
- 渲染
- 瀏覽器輸入 URL 后發生了什么
- 跨域
- 緩存機制
- reflow(回流)和repaint(重繪)
- 渲染層合并
- 編譯(未完成)
- Babel
- 設計模式(未完成)
- 函數式編程(未完成)
- 正則表達式(未完成)
- 性能
- 性能分析
- 性能指標
- 首屏加載
- 優化
- 瀏覽器層面
- HTTP層面
- 代碼層面
- 構建層面
- 移動端首屏優化
- 服務器層面
- bigpipe
- 構建工具
- Gulp
- webpack
- Webpack概念
- Webpack工具
- Webpack優化
- Webpack原理
- 實現loader
- 實現plugin
- tapable
- Webpack打包后代碼
- rollup.js
- parcel
- 模塊化
- ESM
- 安全
- XSS
- CSRF
- 點擊劫持
- 中間人攻擊
- 密碼存儲
- 測試(未完成)
- 單元測試
- E2E測試
- 框架測試
- 樣式回歸測試
- 異步測試
- 自動化測試
- PWA
- PWA官網
- web app manifest
- service worker
- app install banners
- 調試PWA
- PWA教程
- 框架
- MVVM原理
- Vue
- Vue 餓了么整理
- 樣式
- 技巧
- Vue音樂播放器
- Vue源碼
- Virtual Dom
- computed原理
- 數組綁定原理
- 雙向綁定
- nextTick
- keep-alive
- 導航守衛
- 組件通信
- React
- Diff 算法
- Fiber 原理
- batchUpdate
- React 生命周期
- Redux
- 動畫(未完成)
- 異常監控、收集(未完成)
- 數據采集
- Sentry
- 貝塞爾曲線
- 視頻
- 服務端渲染
- 服務端渲染的利與弊
- Vue SSR
- React SSR
- 客戶端
- 離線包
- 第五部分 網絡
- 五層協議
- TCP
- UDP
- HTTP
- 方法
- 首部
- 狀態碼
- 持久連接
- TLS
- content-type
- Redirect
- CSP
- 請求流程
- HTTP/2 及 HTTP/3
- CDN
- DNS
- HTTPDNS
- 第六部分 服務端
- Linux
- Linux命令
- 權限
- XAMPP
- Node.js
- 安裝
- Node模塊化
- 設置環境變量
- Node的event loop
- 進程
- 全局對象
- 異步IO與事件驅動
- 文件系統
- Node錯誤處理
- koa
- koa-compose
- koa-router
- Nginx
- Nginx配置文件
- 代理服務
- 負載均衡
- 獲取用戶IP
- 解決跨域
- 適配PC與移動環境
- 簡單的訪問限制
- 頁面內容修改
- 圖片處理
- 合并請求
- PM2
- MongoDB
- MySQL
- 常用MySql命令
- 自動化(未完成)
- docker
- 創建CLI
- 持續集成
- 持續交付
- 持續部署
- Jenkins
- 部署與發布
- 遠程登錄服務器
- 增強服務器安全等級
- 搭建 Nodejs 生產環境
- 配置 Nginx 實現反向代理
- 管理域名解析
- 配置 PM2 一鍵部署
- 發布上線
- 部署HTTPS
- Node 應用
- 爬蟲(未完成)
- 例子
- 反爬蟲
- 中間件
- body-parser
- connect-redis
- cookie-parser
- cors
- csurf
- express-session
- helmet
- ioredis
- log4js(未完成)
- uuid
- errorhandler
- nodeclub源碼
- app.js
- config.js
- 消息隊列
- RPC
- 性能優化
- 第七部分 總結
- Web服務器
- 目錄結構
- 依賴
- 功能
- 代碼片段
- 整理
- 知識清單、博客
- 項目、組件、庫
- Node代碼
- 面試必考
- 91算法
- 第八部分 工作代碼總結
- 樣式代碼
- 框架代碼
- 組件代碼
- 功能代碼
- 通用代碼