[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算法
- 第八部分 工作代码总结
- 样式代码
- 框架代码
- 组件代码
- 功能代码
- 通用代码