[TOC]
## 在線和離線事件
### 概述
為了構建一個支持離線的 web 應用,你需要知道你的應用何時真正處于離線狀態。同時,你還需要知道應用何時重新回到了「在線」狀態。實際上,我們可以把需求分解成如下內容:
1. 你需要知道用戶何時回到在線狀態,這樣你就可以與服務器重新同步。
2. 你需要知道用戶何時處于離線狀態,這樣你就可以將對服務器的請求放入隊列中以便稍后使用。
### API
**`navigator.onLine`**
[`navigator.onLine`](https://developer.mozilla.org/en/DOM/window.navigator.onLine) 是一個值為 `true`/`false` \(`true` 表示在線, `false` 表示離線\) 的屬性。當用戶通過選擇對應的菜單項 \(Firefox 中為 文件 -> 離線工作\) 切換到「離線模式」時,這個值就會被更新。
#### 注意
如果瀏覽器沒有實現該 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)。
### Storage
DOM存儲的機制是通過存儲字符串類型的鍵/值對,來提供一種安全的存取方式.這個附加功能的目標是提供一個全面的,可以用來創建交互式應用程序的方法\(包括那些高級功能,例如可以離線工作一段時間\).
基于Mozilla的瀏覽器, Internet Explorer 8+, Safari 4+ 以及 Chrome 都提供了自己的DOM存儲規范的實現. \(如果你想讓自己的代碼兼容多個瀏覽器,則你需要照顧一下老版本的IE瀏覽器,IE下有一個類似的特性,在IE8之前版本也可以使用,叫做"[userData behavior](http://msdn.microsoft.com/zh-cn/library/ms531424%28VS.85%29.aspx)",它允許你在多重瀏覽器會話中永久地保存數據.\)
> 以下所提到的對象都是全局對象,作為 [window 對象](https://developer.mozilla.org/zh-cn/DOM/window) 的屬性存在。這意味著可以以 `sessionStorage` 或者 `window.sessionStorage` 的形式訪問這些對象`。`\(這點很重要,因為可以使用iframe來存儲、訪問除了直接包含在頁面的數據之外的附加數據。\)
#### Storage
它是所有Storage實例(`sessionStorage`和`globalStorage[location.hostname]`)的構造函數,設置`Storage.prototype.removeKey = function(key) { this.removeItem(this.key(key)) }`,可通過`localStorage.removeKey`和`sessionStorage.removeKey`訪問到。
> 雖然可以直接通過標準的 JavaScript 屬性訪問方法來設置和讀取值,但是推薦的做法是使用 getItem 和 setItem 方法。
>
> 所有數據在被保存到下面將要介紹的任何一個存儲器之前,都將通過它的`.toString`方法被轉換成字符串。所以一個普通對象將會被存儲為 `"[object Object]"`,而不是對象本身或者它的 JSON 形式。使用瀏覽器自身提供的 JSON 解析和序列化方法來存取對象是比較好的,也是比較常見的方法。
#### sessionStorage
`sessionStorage`是個全局對象,它維護著在頁面會話\(page session\)期間有效的存儲空間。只要瀏覽器開著,頁面會話周期就會一直持續。當頁面重新載入\(reload\)或者被恢復\(restores\)時,頁面會話也是一直存在的。每在新標簽或者新窗口中打開一個新頁面,都會初始化一個新的會話。
```
// 保存數據到當前會話的存儲空間
sessionStorage.setItem("username", "John");
// 訪問數據
alert( "username = " + sessionStorage.getItem("username"));
```
**例子:**
自動保存一個文本域中的內容,如果瀏覽器被意外刷新,則恢復該文本域中的內容,所以不會丟失任何輸入的數據。
```
// 獲取到我們要循環保存的文本域
var field = document.getElementById("field");
// 查看是否有一個自動保存的值
// (只在瀏覽器被意外刷新時)
if ( sessionStorage.getItem("autosave")) {
// 恢復文本域中的內容
field.value = sessionStorage.getItem("autosave");
}
// 每隔一秒檢查文本域中的內容
setInterval(function(){
// 并將文本域的值保存到session storage對象中
sessionStorage.setItem("autosave", field.value);
}, 1000);
```
#### localStorage
`localStorage`和`sessionStorage`一樣是用來鍵值對規則但它是持久性的。
> 當瀏覽器進入私人模式\(private browsing mode,Google Chrome 上對應的應該是叫隱身模式\)的時候,會創建一個新的、臨時的、空的數據庫,用以存儲本地數據\(local storage data\)。當瀏覽器關閉時,里面的所有數據都將被丟棄。
## IndexedDB
**IndexedDB**
是一種低級API,用于客戶端存儲大量結構化數據\(包括, 文件/ blobs\)。該API使用索引來實現對該數據的高性能搜索。雖然
[Web Storage](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Storage_API)對于存儲較少量的數據很有用,但對于存儲更大量的結構化數據來說,這種方法不太有用。**IndexedDB**提供了一個解決方案。
> IndexedDB API是強大的,但對于簡單的情況可能看起來太復雜。如果你更喜歡一個簡單的API,請嘗試類庫,如[localForage](https://localforage.github.io/localForage/), [dexie.js](http://www.dexie.org/), 和 [ZangoDB](https://github.com/erikolson186/zangodb),使IndexedDB更方便用戶。
### 關鍵概念和用法 {#關鍵概念和用法}
IndexedDB是一個事務型數據庫系統,類似于基于SQL的RDBMS。 然而不同的是它使用固定列表,IndexedDB是一個基于JavaScript的面向對象的數據庫。 IndexedDB允許您存儲和檢索用鍵索引的對象; 可以存儲[structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm)支持的任何對象。 您只需要指定數據庫模式,打開與數據庫的連接,然后檢索和更新一系列事務中的數據。
IndexedDB 分別為同步和異步訪問提供了單獨的 API 。同步 API 本來是要用于僅供 [Web Workers](https://developer.mozilla.org/en-US/docs/DOM/Worker)內部使用,但是還沒有被任何瀏覽器所實現。異步 API 在 Web Workers 內部和外部都可以使用。
### 異步 API {#異步_API}
異步 API 方法調用完后會立即返回,而不會阻塞調用線程。要異步訪問數據庫,要調用[window](https://developer.mozilla.org/en-US/docs/DOM/window)對象[`indexedDB`](https://developer.mozilla.org/en-US/docs/IndexedDB/IDBEnvironment#attr_indexedDB)屬性的[`open`](https://developer.mozilla.org/en-US/docs/IndexedDB/IDBFactory#open)`()`方法。該方法返回一個 IDBRequest 對象 \(IDBOpenDBRequest\);異步操作通過在 IDBRequest 對象上觸發事件來和調用程序進行通信。
> `indexedDB`對象在舊版本的瀏覽器上是帶有前綴的 \(在 Gecko <16的情況下是`mozIndexedDB`屬性,Chrome 中是`webkitIndexedDB`,以及IE10 的 `msIndexedDB`\)。
## 在web應用使用文件
使用在HTML5中被加入DOM的File API,使頁面內容請求用戶選擇本地文件,然后讀取這些文件的內容成為可能。選擇可以由使用 HTML[`<input>`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input)元素或者通過drag 和 drop實現。
### 訪問選擇的文件 {#訪問選擇的文件}
```
<input type="file" id="input">
```
File API使訪問包含[`File`](https://developer.mozilla.org/zh-CN/docs/Web/API/File)對象的 [`FileList`](https://developer.mozilla.org/zh-CN/docs/Web/API/FileList)成為可能,FileList代表被用戶選擇的文件。
如果用戶只選擇了一個文件,那么只需要考慮FileList中的第一個File對象。
使用傳統的DOM選擇器訪問一個被選擇的文件。
```
var selectedFile = document.getElementById('input').files[0];
```
通過change事件訪問被選擇的文件,可以通過change事件訪問[`FileList`](https://developer.mozilla.org/zh-CN/docs/Web/API/FileList)(但不是強制的)。
當用戶選擇一個文件時,`handleFiles()`方法會被調用,同時傳入包含[`File`](https://developer.mozilla.org/zh-CN/docs/Web/API/File)對象的[`FileList`](https://developer.mozilla.org/zh-CN/docs/Web/API/FileList)對象。[`File`](https://developer.mozilla.org/zh-CN/docs/Web/API/File)對象代表被用戶選擇的文件。如果你想讓用戶選擇多個文件,只需在input元素上使用`multiple`屬性:
```
<input type="file" id="input" multiple onchange="handleFiles(this.files)">
```
### 獲取被選擇文件的信息 {#獲取被選擇文件的信息}
[`FileList`](https://developer.mozilla.org/zh-CN/docs/Web/API/FileList)對象由DOM提供,列出了所有用戶選擇的文件,每一個代表了一個[`File`](https://developer.mozilla.org/zh-CN/docs/Web/API/File)對象。你可以通過檢查文件列表的length屬性決定用戶可以選則多少文件。
[`File`](https://developer.mozilla.org/zh-CN/docs/Web/API/File)對象提供的三個屬性,包含了關于文件的一些有價值的信息。
name:文件名稱,只讀字符串。只包含文件名稱,不包含任何路徑信息。
size:文件大小,使用bytes描述,是一個只讀的64位整數。
type:文件的MIME type,只讀字符串,當類型不能確定時為`""。`
### 通過click\(\)方法使用隱藏的file input元素 {#通過click()方法使用隱藏的file_input元素}
```
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<a href="#" id="fileSelect">Select some files</a>
<script>
var fileSelect = document.getElementById("fileSelect"),
fileElem = document.getElementById("fileElem");
fileSelect.addEventListener("click", function (e) {
if (fileElem) {
fileElem.click();
}
e.preventDefault(); // prevent navigation to "#"
}, false);
</script>
```
### 使用label元素來觸發一個隱藏的input元素對應的事件 {#使用label元素來觸發一個隱藏的input元素對應的事件}
```
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<label for="fileElem">Select some files</label>
```
### 顯示用戶選擇的圖片的縮略圖 {#例子:顯示用戶選擇的圖片的縮略圖}
```
function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /^image\//;
if (!imageType.test(file.type)) {
continue;
}
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
preview.appendChild(img); // Assuming that "preview" is the div output where the content will be displayed.
var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
}
}
```
這里我們循環處理用戶選擇的文件,看每個文件的type屬性是不是image(通過正則表達式來匹配MIME類型字符串模式"`image/*`")。 對每個文件而言,如果它是圖片,我們就創建一個img元素。可以使用css來創建一個漂亮的邊框或陰影來顯示圖片的具體大小,這兒就不具體做了。
為了在DOM樹中更容易地找到他們,每個圖片元素都被添加了一個名為obj的class。我們還給每個圖片添加了file屬性使它具有[`File`](https://developer.mozilla.org/zh-CN/docs/Web/API/File);這樣做可以讓我們拿到稍后需要實際上傳的圖片。我們在預覽頁中使用[`Node.appendChild()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Node/appendChild)來添加新的縮略圖。
接下來,我們創建了[`FileReader`](https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader)來處理異步的圖片加載并把他賦給圖片元素。在創建一個新的`FileReader`對象后,我們新建了它的`onload`函數,然后調用`readAsDataURL`函數在后臺開始讀取文件的操作。當整個圖片文件被全部加載完后,他們被轉換成了一個被傳遞到onload回調函數的`data:`URL。我們再執行常規操作將img元素的src屬性設置為剛剛加載完畢的URL,使得圖像可以顯示在用戶屏幕上的縮略圖中。
### 使用URLs對象顯示圖片
> **1、 URL.createObjectURL\(\) **靜態方法會創建一個 [`DOMString`](https://developer.mozilla.org/zh-CN/docs/Web/API/DOMString),它的 URL 表示參數中的對象。這個 URL 的生命周期和創建它的窗口中的 [`document`](https://developer.mozilla.org/zh-CN/docs/Web/API/Document)綁定。
>
> 2、在每次調用 `createObjectURL()`方法時,都會創建一個新的 URL 對象,即使你已經用相同的對象作為參數創建過。當不再需要這些 URL 對象時,每個對象必須通過調用 [`URL.revokeObjectURL()`](https://developer.mozilla.org/zh-CN/docs/Web/API/URL/revokeObjectURL) 方法來釋放。瀏覽器會在文檔退出的時候自動釋放它們,但是為了獲得最佳性能和內存使用狀況,你應該在安全的時機主動釋放掉它們。
```
<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<a href="#" id="fileSelect">Select some files</a>
<div id="fileList">
<p>No files selected!</p>
</div>
```
```
window.URL = window.URL || window.webkitURL;
var fileSelect = document.getElementById("fileSelect"),
fileElem = document.getElementById("fileElem"),
fileList = document.getElementById("fileList");
fileSelect.addEventListener("click", function (e) {
if (fileElem) {
fileElem.click();
}
e.preventDefault(); // prevent navigation to "#"
}, false);
function handleFiles(files) {
if (!files.length) {
fileList.innerHTML = "<p>No files selected!</p>";
} else {
fileList.innerHTML = "";
var list = document.createElement("ul");
fileList.appendChild(list);
for (var i = 0; i < files.length; i++) {
var li = document.createElement("li");
list.appendChild(li);
var img = document.createElement("img");
img.src = window.URL.createObjectURL(files[i]);
img.height = 60;
img.onload = function() {
window.URL.revokeObjectURL(this.src);
}
li.appendChild(img);
var info = document.createElement("span");
info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
li.appendChild(info);
}
}
}
```
- 第一部分 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算法
- 第八部分 工作代碼總結
- 樣式代碼
- 框架代碼
- 組件代碼
- 功能代碼
- 通用代碼