# ra-page-storage
**Repository Path**: rasir/ra-page-storage
## Basic Information
- **Project Name**: ra-page-storage
- **Description**: 使用sessionStorage和indexdb对当前页签的数据进行缓存,当页面关闭后缓存的数据失效。
- **Primary Language**: TypeScript
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2023-08-23
- **Last Updated**: 2023-11-27
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ra-page-storage
[English](./README.en.md)
#### 介绍
`page-storage` 使用 `sessionStorage` 和 `indexdb` 对当前页签的数据进行缓存,当页面关闭后缓存的数据失效。
#### 工作原理
1、`page-storage`使用`sessionStorage`缓存当前窗口的`uuid`,当页面刷新时会读取`sessionStorage`中的`uuid`,如果存在则读取缓存数据,不存在则重新生成新的`uuid`。
2、`page-storage` 基于 `indexdb` 封装,使用简单,支持数据缓存,数据删除,数据更新,数据查询等操作,存储在`indexdb`中的`key`为每一个窗口的`uuid`,并且会将`uuid`的数据打上过期时间(`expiredTime`),默认 10s(可以自定义)。
3、`page-storage`使用`web worker`对`indexdb`中数据进行轮询续期,续期周期为过期时间(`expiredTime`)的一半,默认 5s(可以自定义)。
4、`page-storage`还是用了`@rasir/chain-promise-call`方案,让所有操作都工作在链式调用中,保证`indexdb`操作的时续。
5、`page-storage` 所有`api`都支持`promise`操作。
#### 注意事项
1、浏览器兼容性:只要是支持`Promise`的浏览器版本都能兼容。
2、依赖`@rasir/chain-promise-call`。
3、本项目使用的` "core-js": "^3.32.1"`,如果在使用过程中出现兼容问题,请检查`core-js`版本。
4、本文中说是的`链式调用`并不是`jQuery`式的链式调用,而是将所有链式`api`放入一个栈中,当前一个异步函数执行完毕,才会执行下一个函数。保证`indexdb`操作数据存储的时序。
### 快速使用
`npm i @rasir/page-storage -S`
### 使用方法
1、`html`中直接引用`min.js`。
```js
```
2、`npm`使用。
```js
import PageStorage from "@rasir/page-storage";
const storage = new PageStorage({
dbName: "demo_db",
sessionWindowKey: "DEMO_KEY",
});
storage.chainSavePageStorage({ a: 1, b: 2 });
storage.chainGetPageStorage().then((data) => {
console.log(data);
});
```
#### 参数说明
```js
interface IPageStorage {
noWindowName?: boolean; // 是否不使用窗口名称作为窗口特征码,默认 false
windowName?: string; // 当前窗口的特征码,默认 PAGE_STORAGE
windowId?: string; // 当前窗口的uuid
expiredTime?: number; // 过期时间,单位秒,默认 10s
dbName: string; // indexdb中的storeName 必传
sessionWindowKey: string; // 在 sessionStorage 中保存 windowId 的 key 必传
}
```
#### APIs
| API | 说明 | 参数类型 |
| ------------------------ | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `getPageStorage` | 获取当前窗口数据 | `(): Promise` |
| `savePageStorage` | 保存当前窗口数据 | `(data: T): Promise` |
| `updatePageStorage` | 直接修改当前窗口的数据 | `(callback: (data?: T) => T \| Promise): Promise;` |
| `removePageStorage` | 删除当前窗口的数据 | `(): Promise;` |
| `dispose` | 停止给数据续期 | `(): Promise;` |
| `chainGetPageStorage` | 加入链式调用的获取当前窗口数据 | `(): Promise` |
| `chainSavePageStorage` | 加入链式调用的保存当前窗口数据 | `(data: T): Promise;` |
| `chainUpdatePageStorage` | 加入链式调用的直接修改当前窗口的数据 | `(callback: (data?: T) => T \| Promise): Promise;` |
| `chainRemovePageStorage` | 加入链式调用的删除当前窗口的数据 | `(): Promise;` |
| `chainDispose` | 加入链式调用的停止给数据续期 | `(): Promise;` |
| `chainPromiseCall` | 链式调用函数,可以使用`chainPromiseCall.onStatusChange`和`chainPromiseCall.offStatusChange`对实例状态进行监听 | 详见[@rasir/chain-promise-call](https://gitee.com/rasir/chain-promise-call) |
#### 问题和解决方案
- 问题:当使用 `window.open` `从一个页面打开一个新的页面时,sessionStorage` 中的数据会被复制到新的页面。这样会导致我们使用 `sessionWindowKey` 来作为每个页面独立存储的设计失效。
- 解决方案:
1. 使用`window.name` 来给当前页面打标签,因为刷新页面时 `window.name` 不会重置。因此在构造函数中,我添加了 `windowName` 属性,用来判断当前页面是否是新开的。如果页面新开,并且不带 `windowName` 的特征码,就清除 `sessionStorage` 中的 `sessionWindowKey` ,并给 `window.name`设置带特征码的 `name`。当然,如果你不想我的 `window.name` 扰乱了的设计,你可以设置 `noWindowName` 属性,这样你需要自己来保证 `sessionStorage` 的唯一性。
2. 抛弃使用原生的 `window.open` 函数。可以用 `` 标签来进行跳转,或者用模拟 `` 标签点击跳转,如下面这样:
```js
let link = document.createElement("a");
link.href = "http://example.com";
link.target = "_blank";
link.click();
```