记录一些前端数据存储的方法!
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标签引入使用。
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-过期时间(毫秒)
let storage = new Storage();
storage.setItem({//保存(过期时间没有默认值,不设置则不会过期)
key:"name",
value:"小黑"
})
获取:
let value = storage.getItem('name');//获取
console.log('大家好,我是',value);
扩展
localStorage有大小的限制(通常在 2.5-10M之间),有大数据量存储需求可以使用插件localForage。
localForage使得离线数据存储在任何浏览器都是一项容易的任务。若浏览器不支持 IndexedDB 或 WebSQL,则使用 localStorage。localForage 的使用方法与localStorage相似很容易上手,可以查看官方文档了解。
默认情况下,localForage 按照以下顺序选择数据仓库的后端驱动:
- IndexedDB
- WebSQL
- localStorage
注意:vue-cli开发的项目中使用,可以查看这篇文档。
应用场景:移动APP开发,数据保存在本地,无大小限制。(表数据也可以使用json格式保存)
前端数据库
IndexedDB API是强大的,但对于简单的情况可能看起来太复杂。如果你更喜欢一个简单的API,请尝试 localForage、dexie.js、PouchDB、idb、idb-keyval、JsStore 或者 lovefield 之类的库,这些库使 IndexedDB 对开发者来说更加友好。
注意:Web SQL兼容性不好,一般使用基于IndexedDB API的第三方库来简化数据存储操作。
案例
WebSQL案例,了解学习即可,Web SQL的兼容性并不是特别理想,仅chrome ,safari,opera 10.5+等浏览器支持。
封装DaoTools工具
封装DaoTools工具(一个json对象),可以保存在单独的js文件中,通过script标签引入使用。
根据需要创建数据库,编写相应的crud函数,也可以直接调用transaction函数使用sql语句进行crud操作。
//前端数据库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
方式调用其中封装的函数即可。
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
原文链接:前端数据存储