diff --git a/6-data-storage/02-localstorage/1-form-autosave/task.md b/6-data-storage/02-localstorage/1-form-autosave/task.md index b2e0a42228..9f667c7773 100644 --- a/6-data-storage/02-localstorage/1-form-autosave/task.md +++ b/6-data-storage/02-localstorage/1-form-autosave/task.md @@ -1,10 +1,9 @@ +# 自动保存表单域 -# Autosave a form field +创建一个 `textarea`,每当值发生变化时,可以自动保存。 -Create a `textarea` field that "autosaves" its value on every change. +因此,如果用户偶尔关闭了页面,然后重新打开,他会发现之前输入的值仍然保留着。 -So, if the user occasionally closes the page, and opens it again, he'll find his unfinished input at place. - -Like this: +像这样: [iframe src="solution" height=120] diff --git a/6-data-storage/02-localstorage/article.md b/6-data-storage/02-localstorage/article.md index 2e24affba5..5c469e6082 100644 --- a/6-data-storage/02-localstorage/article.md +++ b/6-data-storage/02-localstorage/article.md @@ -1,54 +1,54 @@ # LocalStorage, sessionStorage -Web storage objects `localStorage` and `sessionStorage` allow to save key/value pairs in the browser. +Web 存储对象 `localStorage` 和 `sessionStorage` 允许我们在浏览器上保存键值对。 -What's interesting about them is that the data survives a page refresh (for `sessionStorage`) and even a full browser restart (for `localStorage`). We'll see that very soon. +有趣的是,数据在页面刷新(`sessionStorage`)甚至浏览器完全重启(`localStorage`)后仍然保留。我们很快会看到。 -We already have cookies. Why additional objects? +我们已经有了 `cookies`。为什么还要额外的 web 存储对象呢? -- Unlike cookies, web storage objects are not sent to server with each request. Because of that, we can store much more. Most browsers allow at least 2 megabytes of data (or more) and have settings to configure that. -- Also unlike cookies, the server can't manipulate storage objects via HTTP headers. Everything's done in JavaScript. -- The storage is bound to the origin (domain/protocol/port triplet). That is, different protocols or subdomains infer different storage objects, they can't access data from each other. +- 与 `cookies` 不同,web 存储对象不会随着每次请求发送到服务端。因此,我们可以保存更多数据。大部分浏览器允许保存至少 2M 字节的数据(或者更多),并且是可配置的。 +- 还有一点和 `cookies` 不同,服务端不能通过 HTTP 头部操作存储对象。一切都在 `JavaScript` 中完成。 +- 存储绑定在同一个源(`域名/协议/端口 三者都相同`)下。也就是说,不同协议或者子域保存不同的存储对象,它们之间不能相互访问数据。 -Both storage objects provide same methods and properties: +两个存储对象都提供相同的方法和属性: -- `setItem(key, value)` -- store key/value pair. -- `getItem(key)` -- get the value by key. -- `removeItem(key)` -- remove the key with its value. -- `clear()` -- delete everything. -- `key(index)` -- get the key on a given position. -- `length` -- the number of stored items. +- `setItem(key, value)` -- 存储键值对。 +- `getItem(key)` -- 根据键名获取值。 +- `removeItem(key)` -- 删除单个数据。 +- `clear()` -- 删除所有数据。 +- `key(index)` -- 获取该索引下的键名。 +- `length` -- 存储数据的长度。 -As you can see, it's like a `Map` collection (`setItem/getItem/removeItem`), but also keeps elements order and allows to access by index with `key(index)`. +正如你所看到的,它就像一个 `Map` 收集器(`setItem/getItem/removeItem`)。但是也保持着元素顺序,并且允许通过索引访问 `key(index)` 。 -Let's see how it works. +让我们看看它是如何工作的吧。 -## localStorage demo +## localStorage 示例 -The main features of `localStorage` are: +`localStorage` 最主要的特点是: -- Shared between all tabs and windows from the same origin. -- The data does not expire. It remains after the browser restart and even OS reboot. +- 同源的数据在所有浏览器标签页和窗口之间共享。 +- 数据不会过期。它在浏览器重启甚至系统重启后仍然保留。 -For instance, if you run this code... +例如,如果你运行此代码…… ```js run localStorage.setItem('test', 1); ``` -...And close/open the browser or just open the same page in a different window, then you can get it like this: +……然后关闭重新打开浏览器或者只是在不同的窗口打开同一页面,然后你就能看到: ```js run alert( localStorage.getItem('test') ); // 1 ``` -We only have to be on the same origin (domain/port/protocol), the url path can be different. +我们只要求数据存储在同源上(域名/端口/协议都相同),`url` 路径可以是不同的。 -The `localStorage` is shared between all windows with the same origin, so if we set the data in one window, the change becomes visible in another one. +同源的 `localStorage` 数据在所有窗口之间都是共享的。所以,如果我们在其中一个窗口设置了数据,在另外一个窗口中可以看到数据也发生了变化。 -## Object-like access +## 类似对象形式访问 -We can also use a plain object way of getting/setting keys, like this: +我们也可以使用普通对象读取/设置键的方式,像这样: ```js run // set key @@ -61,23 +61,24 @@ alert( localStorage.test ); // 2 delete localStorage.test; ``` -That's allowed for historical reasons, and mostly works, but generally not recommended for two reasons: +这是历史原因允许的,并且大部分是有效的,但是通常不推荐这种做法,原因如下: -1. If the key is user-generated, it can be anything, like `length` or `toString`, or another built-in method of `localStorage`. In that case `getItem/setItem` work fine, while object-like access fails: - ```js run - let key = 'length'; - localStorage[key] = 5; // Error, can't assign length - ``` +1. 如果键是由用户生成的,那么它可以是任何内容,例如 `length` 或 `toString`,或者是其他 `localStorage` 的内置方法。在这种情况下,`getItem/setItem` 可以正常使用,类似对象访问的方式则会失败: -2. There's a `storage` event, it triggers when we modify the data. That event does not happen for object-like access. We'll see that later in this chapter. +```js run +let key = 'length'; +localStorage[key] = 5; // 错误,不能指定长度 +``` + +2. 有一个 `storage` 事件,在我们改变数据时会触发。但是以类似对象形式访问时,该事件不会触发。我们可以在本章节后面看到。 -## Looping over keys +## 循环键 -As we've seen, the methods provide "get/set/remove by key" functionality. But how to get all saved values or keys? +正如我们看到的,这些方法提供了按键获取/设置/删除的功能。但是我们怎么能够获取到所有保存的值或键呢? -Unfortunately, storage objects are not iterable. +不幸的是,存储对象是不可迭代的。 -One way is to loop over them as over an array: +一种方法是在数组上循环遍历它们: ```js run for(let i=0; i { if (event.key != 'now') return; alert(event.key + ':' + event.newValue + " at " + event.url); @@ -210,40 +209,41 @@ window.onstorage = event => { localStorage.setItem('now', Date.now()); ``` -Please note that the event also contains: `event.url` -- the url of the document where the data was updated. +请注意,该事件还包括 `event.url` -- 数据更新了的文档链接。 + +此外,`event.storageArea` 还会返回存储对象 -- 因为 `sessionStorage` 和 `localStorage` 具有相同的事件,所以 `event.storageArea` 会返回数据发生改变的存储对象。为了响应数据更新,我们也许会在里面设置一些东西。 -Also, `event.storageArea` contains the storage object -- the event is the same for both `sessionStorage` and `localStorage`, so `storageArea` references the one that was modified. We may even want to set something back in it, to "respond" to a change. +** 这允许同源的不同窗口交换消息。 ** -**That allows different windows from the same origin to exchange messages.** +现代浏览器还支持 [Broadcast channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API),这是用于同源窗口之间通信的特殊 API,它的功能更加全面,但是兼容性还不好。有一些库可以基于 `localStorage` polyfill 该 API,使其可以用在任何地方。 -Modern browsers also support [Broadcast channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API), the special API for same-origin inter-window communication, it's more full featured, but less supported. There are libraries that polyfill that API, based on `localStorage`, that make it available everywhere. +## 总结 -## Summary +Web 存储对象 `localStorage` 和 `sessionStorage` 允许我们在浏览器中保存键值对。 -Web storage objects `localStorage` and `sessionStorage` allow to store key/value in the browser. -- Both `key` and `value` must be strings. -- The limit is 2mb+, depends on the browser. -- They do not expire. -- The data is bound to the origin (domain/port/protocol). +- 所有的 `key` 和 `value` 都必须是字符串。 +- 存储大小限制为 2mb+,取决于浏览器也会有所不同。 +- 它们不会过期。 +- 数据绑定在同源下(域名/端口/协议都相同)。 | `localStorage` | `sessionStorage` | |----------------|------------------| -| Shared between all tabs and windows with the same origin | Visible within a browser tab, including iframes from the same origin | -| Survives browser restart | Survives page refresh (but not tab close) | +| 同源的所有标签页和窗口之间共享数据 | 作用域在一个浏览器标签下,包括同源的 iframes | +| 浏览器重启后数据仍然保留 | 页面刷新后数据仍然保留(不包括标签页关闭) | -API: +API: -- `setItem(key, value)` -- store key/value pair. -- `getItem(key)` -- get the value by key. -- `removeItem(key)` -- remove the key with its value. -- `clear()` -- delete everything. -- `key(index)` -- get the key number `index`. -- `length` -- the number of stored items. -- Use `Object.keys` to get all keys. -- We access keys as object properties, in that case `storage` event isn't triggered. +- `setItem(key, value)` -- 存储键值对。 +- `getItem(key)` -- 根据键名获取值。 +- `removeItem(key)` -- 删除单个数据。 +- `clear()` -- 删除所有数据。 +- `key(index)` -- 获取该索引下的键名。 +- `length` -- 存储数据的长度。 +- 使用 `Object.keys` 获取所有的键。 +- 假如我们使用对象属性的形式来访问键,则 `storage` 事件不会被触发。 -Storage event: +Storage 事件: -- Triggers on `setItem`, `removeItem`, `clear` calls. -- Contains all the data about the operation, the document `url` and the storage object. -- Triggers on all `window` objects that have access to the storage except the one that generated it (within a tab for `sessionStorage`, globally for `localStorage`). +- 在调用 `setItem`,`removeItem`,`clear`方法后触发。 +- 返回包含有关操作(`key/oldValue/newValue`),文档 `url` 和存储对象(`storageArea`)的所有数据。 +- 在除当前数据改变的对象以外所有能访问到存储对象的 `window` 对象上都会被触发(在 `sessionStorage` 有效范围的同一标签页下,在 `localStorage` 的有效范围下)。