storage【持久化存储】 🔥
描述
对浏览器自带的 localStorage 和 sessionStorage 进行封装,特点支持 加密、解密、过期时间处理。
⚠️ 警告
使用该方法,是依赖 crypto-js (opens new window)
# 1.依赖 crypto-js 库安装
yarn add crypto-js@4.1.1
1
npm i crypto-js@4.1.1
1
// Make sure to add code blocks to your code group
# 2.示例
# 2.1 设置默认配置
import storage from 'sf-utils2/lib/expand/storage.js'
storage.__config = {
type: 'localStorage', // 本地存储类型 可选值:localstorage sessionStorage
prefix: 'sfutils_0.0.1', // 存储key名称前缀 建议:项目名 + 项目版本
expire: 0, //设置默认过期时间 单位:秒
isEncrypt: true // 默认加密 为了调试方便, 开发过程中可以不加密
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2.2 setItem(key, value, expire = 0) 设置值
// 设置3s过期
storage.setItem('key', { id: '001', name: '蔡徐坤' }, 3)
// 输出
// 未加密:sfutils_0.0.1_key {"value":{"id":"001","name":"蔡徐坤"},"time":1655989214459,"expire":3000}
// 加密:5011bf7d42b8ad9596ae69c310d00da437debac370d6588f2d05a847eb1810b213db14762a3f595daf30586fd65ec0ab8605546f9462d09286c867c9a7570b3e045dbecc65ed20ede499cc2375e41282
1
2
3
4
5
2
3
4
5
# 2.3 getItem(key, autoRetain = false) 获取值
// 读取
storage.getItem('key') // {"id": "001","name": "蔡徐坤"}
// 读取 未过期期间被调用 则自动续期 进行保活
storage.getItem('key', true) // {"id": "001","name": "蔡徐坤"}
1
2
3
4
5
2
3
4
5
# 2.4 has(key) 是否存在 key
storage.has('key') // true
1
# 2.5 getKeys() 获取所有的 keys 数组
storage.getKeys() // ["sfutils_0.0.1_key","23232_key","loglevel:webpack-dev-server"]
1
# 2.6 getForIndex(index) 根据索引获取 key
storage.getForIndex(0) // sfutils_0.0.1_key {"value":{"id":"001","name":"蔡徐坤"},"time":1655989214459,"expire":3000}
1
# 2.7 getLength() 根据索引获取 key 长度
storage.getLength(0) // 3
1
# 2.8 getItemsAll() 获取全部
storage.getItemsAll()
//输出: [
// {
// "key": "mode",
// "val": "\"read\""
// },
// {
// "key": "sfutils_0.0.1_key",
// "val": "5011bf7d42b8ad9596ae69c310d00da437debac370d6588f2d05a847eb1810b213db14762a3f595daf30586fd65ec0abd4790ea1bc55f57badecd163ebe036367d995e42b919f1a04de3b77fc7489f00"
// },
// {
// "key": "23232_key",
// "val": "5011bf7d42b8ad9596ae69c310d00da437debac370d6588f2d05a847eb1810b213db14762a3f595daf30586fd65ec0abe35c99c73de6a965e65af0468df2d60d8f784d5cd9a022e67a23c73317f08ccd"
// },
// {
// "key": "loglevel:webpack-dev-server",
// "val": "ERROR"
// }
// ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 2.8 removeItem(key) 根据 key 删除某一个 item
storage.removeItem('key')
1
# 2.9 clear() 清空所有缓存
storage.clear()
1
# 3.0 encrypt(data) 加密
storage.encrypt({ id: '测试', name: '你好呀' })
// 输出:493cd6eb5a881c07d8f630deda3f85285a31fcf2efa94995b4e38d2b6d964845ade5059ec4df4da9398d7ba019aef82d
1
2
2
# 3.1 decrypt(data) 解密
storage.decrypt({ id: '测试', name: '你好呀' })
// 输出:{"id":"测试","name":"你好呀"}
1
2
2
# 3.源码
源码,点开查看 👈
/***
* @title: storage.js
* @Author: bianpengfei
* @create 2022/6/22 23:23
* @Description: 对存储的简单封装
*/
import CryptoJS from 'crypto-js'
// 十六位十六进制数作为密钥
const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161')
// 十六位十六进制数作为密钥偏移量
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a')
const _storage = {
__config: {
// 类型 window.localStorage,window.sessionStorage,
type: 'localStorage', // 本地存储类型 sessionStorage
prefix: 'sfutils_0.0.1', // 名称前缀 建议:项目名 + 项目版本
expire: 1, //过期时间 单位:秒
isEncrypt: true // 默认加密 为了调试方便, 开发过程中可以不加密
},
// 判断是否支持 Storage
isSupport() {
return typeof Storage !== 'undefined'
},
/**
* 设置item
* @param {String} key 键名
* @param {any} value 值
* @param {Number} expire 过期时间 单位秒
*/
setItem(key, value, expire = 0) {
if (value === '' || value === null || value === undefined) {
value = null
}
if (isNaN(expire) || expire < 0) throw new Error('Expire must be a number')
expire = (expire ? expire : this.__config.expire) * 1000
let data = {
value: value, // 存储值
time: Date.now(), //存值时间戳
expire: expire // 过期时间
}
const encryptString = this.__config.isEncrypt ? this.encrypt(JSON.stringify(data)) : JSON.stringify(data)
window[this.__config.type].setItem(this.autoAddPrefix(key), encryptString)
},
/**
* 获取key
* @param {String} key 键名
* @param {Boolean} autoRetain 是否自动延续
* @returns {null|*}
*/
getItem(key, autoRetain = false) {
key = this.autoAddPrefix(key)
// key 不存在判断
if (
!window[this.__config.type].getItem(key) ||
JSON.stringify(window[this.__config.type].getItem(key)) === 'null'
) {
return null
}
// 优化 持续使用中续期
const storage = this.__config.isEncrypt
? JSON.parse(this.decrypt(window[this.__config.type].getItem(key)))
: JSON.parse(window[this.__config.type].getItem(key))
let nowTime = Date.now()
// 过期删除
if (storage.expire && storage.expire < nowTime - storage.time) {
console.log('带内', this.__config.expire, nowTime - storage.time)
this.removeItem(key)
return null
} else {
// 未过期期间被调用 则自动续期 进行保活
autoRetain && this.setItem(this.autoRemovePrefix(key), storage.value)
return storage.value
}
},
/**
* 是否存在
* @param {String} key
* @returns {boolean}
*/
has(key) {
key = this.autoAddPrefix(key)
let arr = this.getItemsAll().filter(item => {
return item.key === key
})
return !!arr.length
},
/**
* 获取所有的keys 数组
* @returns {*[]}
*/
getKeys() {
let items = this.getItemsAll()
let keys = []
for (let index = 0; index < items.length; index++) {
keys.push(items[index].key)
}
return keys
},
/**
* 根据索引获取key
* @param {Number} index
* @returns {*}
*/
getForIndex(index) {
return window[this.__config.type].key(index)
},
/**
* 获取localStorage长度
* @returns {*}
*/
getLength() {
return window[this.__config.type].length
},
/**
* 获取全部
* @returns {*[]}
*/
getItemsAll() {
let len = window[this.__config.type].length // 获取长度
let arr = [] // 定义数据集
for (let i = 0; i < len; i++) {
// 获取key 索引从0开始
let getKey = window[this.__config.type].key(i)
// 获取key对应的值
let getVal = window[this.__config.type].getItem(getKey)
// 放进数组
arr[i] = { key: getKey, val: getVal }
}
return arr
},
/**
* 根据key 删除某一个item
* @param {String} key
*/
removeItem(key) {
window[this.__config.type].removeItem(this.autoAddPrefix(key))
},
/**
* 清空
*/
clear() {
window[this.__config.type].clear()
},
/**
* 名称前自动添加前缀
* @param {String} key
*/
autoAddPrefix(key) {
const prefix = this.__config.prefix ? this.__config.prefix + '_' : ''
return prefix + key
},
/**
* 移除已添加的前缀
* @param {String} key
*/
autoRemovePrefix(key) {
const len = this.__config.prefix ? this.__config.prefix.length + 1 : ''
return key.substr(len)
},
/**
* 加密方法
* @param data
* @returns {string}
*/
encrypt(data) {
if (typeof data === 'object') {
try {
data = JSON.stringify(data)
} catch (error) {
console.log('encrypt error:', error)
}
}
const dataHex = CryptoJS.enc.Utf8.parse(data)
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return encrypted.ciphertext.toString()
},
/**
* 解密方法
* @param data
* @returns {string}
*/
decrypt(data) {
const encryptedHexStr = CryptoJS.enc.Hex.parse(data)
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr)
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
iv: SECRET_IV,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
return decryptedStr.toString()
}
}
export default _storage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
上次更新: 2025/07/01, 14:52:29