0%

前端数据存储

记录一些前端数据存储的方法!

JS文件

把一些常用数据(json对象、字符串等)保存在js文件中,通过script标签引入使用。

创建

创建js文件

引入

script引入js文件。./代表当前目录,../代表上级目录。

使用

使用js文件中的数据、变量、函数、类等。

扩展

vue-cli开发的项目中,想在.vue文件中导入js文件。笔记见:VUE-汇总/导入js文件

Storage API

Web Storage 包含如下两种机制:

  • sessionStorage 为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。
  • localStorage 同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在(大小限制通常在 2.5-10M之间)。

案例

localStorage案例,给localStorage设置过期时间

封装Storage类

封装Storage类,可以保存在单独的js文件中,通过script标签引入使用。

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
class Storage {
constructor(key) {
this.key = 'storage';
}
//设置缓存
setItem(params) {
let obj = {
key: '',
value: '',
expires: "",
startTime: new Date().getTime() //记录何时将值存入缓存,毫秒级
}
let options = {};
//将obj和传进来的params合并
Object.assign(options, obj, params);
if (options.expires) {
//如果options.expires设置了的话
//以options.key为key,options为值放进去
localStorage.setItem(options.key, JSON.stringify(options));
} else {
//如果options.expires没有设置,就判断一下value的类型
let type = Object.prototype.toString.call(options.value);
//如果value是对象或者数组对象的类型,就先用JSON.stringify转一下,再存进去
if (Object.prototype.toString.call(options.value) == '[object Object]') {
options.value = JSON.stringify(options.value);
}
if (Object.prototype.toString.call(options.value) == '[object Array]') {
options.value = JSON.stringify(options.value);
}
localStorage.setItem(options.key, options.value);
}
}
//拿到缓存
getItem(key) {
let item = localStorage.getItem(key);
if (item != null) {
//先将拿到的试着进行json转为对象的形式
try {
item = JSON.parse(item);
} catch (error) {
//如果不行就不是json的字符串,就直接返回
item = item;
}
//如果有startTime的值,说明设置了失效时间
if (item.startTime != null) {
let date = new Date().getTime();
//何时将值取出减去刚存入的时间,与item.expires比较,如果大于就是过期了,如果小于或等于就还没过期
if (date - item.startTime > item.expires) {
//缓存过期,清除缓存,返回false
localStorage.removeItem(key);
return false;
} else {
//缓存未过期,返回值
return item.value;
}
} else {
//如果没有设置失效时间,直接返回值
return item;
}
} else {
return null;
}
}
//移出缓存
removeItem(key) {
localStorage.removeItem(key);
}
//移出全部缓存
clear() {
localStorage.clear();
}
}

使用

保存:

保存:参数可以设置三个,name-作为键key,value-作为值value,expires-过期时间(毫秒)

1
2
3
4
5
let storage = new Storage();
storage.setItem({//保存(过期时间没有默认值,不设置则不会过期)
key:"name",
value:"小黑"
})

获取:

1
2
let value = storage.getItem('name');//获取
console.log('大家好,我是',value);

扩展

localStorage有大小的限制(通常在 2.5-10M之间),有大数据量存储需求可以使用插件localForage

localForage使得离线数据存储在任何浏览器都是一项容易的任务。若浏览器不支持 IndexedDB 或 WebSQL,则使用 localStorage。localForage 的使用方法与localStorage相似很容易上手,可以查看官方文档了解。

默认情况下,localForage 按照以下顺序选择数据仓库的后端驱动:

  1. IndexedDB
  2. WebSQL
  3. localStorage

注意:vue-cli开发的项目中使用,可以查看这篇文档

应用场景:移动APP开发,数据保存在本地,无大小限制。(表数据也可以使用json格式保存)

前端数据库

前端数据库——WebSQLIndexedDB

IndexedDB API是强大的,但对于简单的情况可能看起来太复杂。如果你更喜欢一个简单的API,请尝试 localForagedexie.jsPouchDBidbidb-keyvalJsStore 或者 lovefield 之类的库,这些库使 IndexedDB 对开发者来说更加友好。

注意:Web SQL兼容性不好,一般使用基于IndexedDB API的第三方库来简化数据存储操作。

案例

WebSQL案例,了解学习即可,Web SQL的兼容性并不是特别理想,仅chrome ,safari,opera 10.5+等浏览器支持。

封装DaoTools工具

封装DaoTools工具(一个json对象),可以保存在单独的js文件中,通过script标签引入使用。

根据需要创建数据库,编写相应的crud函数,也可以直接调用transaction函数使用sql语句进行crud操作。

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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//前端数据库Web SQL,Web SQL的兼容性并不是特别理想,仅chrome ,safari,opera 10.5+等浏览器支持。
//注意:数据库操作是异步的,需要采用回调函数的方式操作数据库
DaoTools = {
//数据库操作对象
db: null,
//初始化数据库对象
init: function() {
if (typeof openDatabase == 'undefined') {
alert('当前浏览器不支持Web SQL,建议使用Chrome浏览器!');
return;
}
//参数分别为:数据库名称、版本号、描述文本、数据库大小、创建回调
//若不存在则创建
this.db = openDatabase('myDB', '1.0', '前端数据库,Web SQL', 1024 * 1024 * 10);
//transaction 数据库的事务函数(在其中使用executeSql函数执行sql。有一个executeSql执行失败都会回滚)
this.db.transaction(function(tx) {
//executeSql函数:
// 第一个参数为sql语句;第二个参数为sql语句中占位符?对应的数据(数组);第三、四个参数为成功和失败时的回调函数

//若不存在表userinfo则创建。列名 username,数据类型 TEXT;列名 password,数据类型 TEXT;。。。
tx.executeSql(
'CREATE TABLE IF NOT EXISTS userinfo(username TEXT,password TEXT, email TEXT)', []);
//创建系统变量表(保存键值对key/value)
tx.executeSql('CREATE TABLE IF NOT EXISTS sysparam(key TEXT,value TEXT)', []);
//往userinfo表中插入一条数据
DaoTools.addUser({
username: 'admin',
password: '12345',
email: '1135637451@qq.com'
});
});
},
//预留transaction接口,用于执行sql。通过DaoTools.transaction()调用
transaction: function(backCall) {
DaoTools.db.transaction(backCall);
},

/**
* 执行sql,增删改查
* @param {string} sql sql语句
* @param {string[]} params ?占位符对应的数据,数组
* @param {requestCallback} hdcall sql执行成功后的回调
*/
update: function(sql, params, hdcall) {
DaoTools.db.transaction(function(tx) {
tx.executeSql(sql, params,
function(tx, rs) {
console.log('sql执行成功!');
if (hdcall) hdcall();
},
function(tx, error) {
console.error('sql执行失败!\r\n' + error.source + "::" + error.message);
}
);
});
},

/**
* 获取用户信息
* @param {string} username 用户名(账号)
* @param {requestCallback} backCall 回调(接收数据)
* @return {Object} 用户信息
*/
getUserinfo: function(username, backCall) {
DaoTools.db.transaction(function(tx) {
//执行查询
tx.executeSql('SELECT * FROM userinfo WHERE username = ?', [username],
function(tx, rs) {
var json = {};
if (rs.rows.length > 0) {
json = rs.rows.item(0);
}
backCall(json);
},
function(tx, error) {
console.error(error.source + "::" + error.message);
}
);
});
},

/**
* 新增用户
* @param {Object} userData 用户名username、密码password为必填项
* @param {requestCallback} backCall 回调
* @return {string} errMsg 若用户信息不完整,则会返回错误信息
*/
addUser: function(userData, backCall) {
var errMsg = '';
//用户名、密码必填
if (!userData || !userData.username || !userData.password) {
errMsg = '请完善用户信息!';
if (backCall) backCall(errMsg);
return;
}
//先查询,用户名不能相同
DaoTools.getUserinfo(userData.username, data => {
if (Object.keys(data).length > 0) {
errMsg = '存在同名用户!';
if (backCall) backCall(errMsg);
return;
}
DaoTools.db.transaction(function(tx) {
//新增数据
tx.executeSql(
'INSERT INTO userinfo(username,password,email) VALUES(?,?,?)',
[userData.username, userData.password, userData.email ? userData.email :
''
],
function(tx, rs) {
console.log(`新增用户${userData.username}成功`);
if (backCall) backCall();
},
function(tx, error) {
console.error(error.source + "::" + error.message);
}
);
});
});
},

//获取系统常用变量
getParam: function(key, backCall) {
DaoTools.db.transaction(function(tx) {
//执行查询
tx.executeSql('SELECT * FROM sysparam WHERE key = ?', [key],
function(tx, rs) {
var v = '';
if (rs.rows.length > 0) {
v = rs.rows.item(0).value;
}
backCall(v);
},
function(tx, error) {
console.error(error.source + "::" + error.message);
}
);
});
},

//保存系统常用变量
setParam: function(key, value, backCall) {
DaoTools.db.transaction(function(tx) {
//先删除再新增
tx.executeSql('DELETE FROM sysparam WHERE key = ?', [key]);
//新增数据
tx.executeSql('INSERT INTO sysparam(value, key) VALUES(?, ?)', [value, key],
function(tx, rs) {
if (backCall) backCall();
console.log(key + "::" + value)
},
function(tx, error) {
console.error(error.source + "::" + error.message);
}
);
});
},

/**
* 查询所有数据
* @param {string} tableName 表名
* @param {requestCallback} backCall 回调(接收数据)
* @return {Object[]} 数组
*/
queryAll: function(tableName, backCall) {
DaoTools.db.transaction(function(tx) {
tx.executeSql(`select * from ${tableName}`, [],
function(tx, rs) {
var json = [];
for (var i = 0; i < rs.rows.length; i++) {
json[i] = rs.rows.item(i);
}
backCall(json);
},
function(tx, error) {
console.error(error.source + "::" + error.message);
}
);
});
},

/**
* 通用查询数据,支持分页
* @param {string} sql sql语句
* @param {string[]} params ?占位符对应的数据,数组
* @param {requestCallback} backCall 回调(接收数据)
* @param {string} pageSize 页面大小(一页的数据量)
* @param {string} pageIndex 页码(从1开始)
* @return {Object[]} 数组
*/
query: function(sql, params, backCall, pageSize, pageIndex) {
DaoTools.db.transaction(function(tx) {
//传入的页序号是从1开始的,需要-1
if (pageSize && pageIndex) {
sql = sql + ' limit ' + pageSize + ' offset ' + pageSize * (pageIndex - 1);
pageIndex = pageIndex - 1;
}
console.log(`sql = ${sql}`);

if (!params) params = [];

tx.executeSql(sql, params,
function(tx, rs) {
var json = [];
for (var i = 0; i < rs.rows.length; i++) {
json[i] = rs.rows.item(i);
}
backCall(json);
},
function(tx, error) {
console.error(error.source + "::" + error.message);
}
);
});
},

/**
* 清除数据库信息,初始化
*/
clear: function() {
var me = this,
cnt = 0;
var cb = function() { //重新创建表对象
cnt++;
if (cnt == 2) { //确保两张表都删掉了,再初始化
me.init();
alert('初始化成功!');
}
};

this.db.transaction(function(tx) {
tx.executeSql('DROP TABLE userinfo', [], cb);
tx.executeSql('DROP TABLE sysparam', [], cb);
});
},
};

//初始化(匿名函数,立即执行)
//script标签引入该js文件后,就会初始化数据库
(function() {
DaoTools.init();
})();

使用

DaoTools是一个json对象,直接DaoTools.queryAll方式调用其中封装的函数即可。

1
2
3
4
5
6
7
8
9
10
11
DaoTools.queryAll('userinfo',data=>{
console.log(`userinfo表的数据 = \r\n ${JSON.stringify(data)}`);
// userinfo表的数据 =
// [{"username":"admin","password":"12345","email":"1135637451@qq.com"}]
})

DaoTools.getUserinfo('admin',data=>{
console.log(`用户admin的信息 = \r\n ${JSON.stringify(data)}`);
// 用户admin的信息 =
// {"username":"admin","password":"12345","email":"1135637451@qq.com"}
})

扩展

Web SQL的兼容性并不是特别理想,归咎其原因,主要是因为 Web SQL Database API 实际上并不包含在 HTML5 规范之中。它是一个独立的规范,它引入了一套使用 SQL 操作客户端数据库的 API。其规范已经被停止更新了,所以大多数浏览器并不支持。
Web SQL相对于 sessionStorage ,locationStorage最大的优势 :能方便的进行对象存储、能进行大量的数据的处理。

总结

  • 主要用于PC端的web 应用,想使用sql语句进行数据crud操作,可以使用Web SQL
  • 页面传递参数、状态记录等小数据量场景,可以考虑Storage API
  • 不是上边的应用场景,建议使用插件localForage
若图片不能正常显示,请在浏览器中打开

欢迎关注我的其它发布渠道