一篇文章学会IndexedDB
【简介】
IndexedDB,web端可以直接使用的数据库,详见: https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API
【IndexedDB vs LocalStorage】
之前介绍了LocalStorage:一篇文章学会localStorage,
大部分场景下LocalStorage已经可以满足使用了,但还是有一些缺陷,
下面对比一下IndexedDB和LocalStorage的不同
容量大小
|—LocalStorage:最大5M
|—IndexedDB:250M+
数据库特性
|—LocalStorage:只是保存数据,不具备其他特性
|—IndexedDB:具备数据库特性,数据库,表,主键,索引,排序等
同步异步
|—LocalStorage:同步操作
|—IndexedDB:异步操作
简单总结
|—LocalStorage只是本地存储,类似一个小文件存取内容,
|—IndexedDB是web端的数据库,存取数据,搜索数据,数据排序,事务等都支持,而且容量很大
【IndexedDB:数据库和表】
同样的,由于IndexedDB的功能很强大,
使用也稍微复杂,需要一些数据库的基础知识,
创建数据库
要操作IndexedDB,首先需要有一个数据库,创建数据库代码如下
window.indexedDB.open(databaseName);
如果数据库的表结构等发生了变化,需要传入一个新的version再次创建一下
window.indexedDB.open(databaseName, version);
最终返回的db对象在onsuccess回调,或者onupgradeneeded回调内,最终代码如下
/**
* open db
* @param {*} databaseName
* @param {*} version
* @returns
*/
export const openDB = (databaseName, version) => {
return new Promise((resolve, reject) => {
const request = version ? window.indexedDB.open(databaseName, version) : window.indexedDB.open(databaseName);
request.onerror = (event) => {
reject(event.target.error);
};
request.onsuccess = () => {
resolve(request.result);
};
request.onupgradeneeded = (event) => {
resolve(event.target.result);
};
});
};
创建成功后可以在chrome devtools中的application-storage-IndexedDB内看到创建好的db

查询数据库
创建好后,可以查询一下目前有哪些数据库,代码如下
indexedDB.databases();
会返回目前本地的数据库列表:

删除数据库
当数据库不需要时,可以删除数据库,代码如下
indexedDB.deleteDatabase(databaseName);
创建表
当创建好数据库db后,就可以创建表了
db.createObjectStore(table.name, key);
这里需要传入表名和key
创建索引
创建好表后就可以创建索引了,如下
os.createIndex(name, index, { unique: unique });
创建好表和索引后,在db下就会显示

删除表
删除表,比较简单, 代码如下
db.deleteObjectStore(tableName);
【IndexedDB:操作数据】
创建好数据库和表后,就可以开始操作数据了,
添加数据
需要先创建一个事务,然后添加数据,如下
const tx = db.transaction([tableName], 'readwrite');
const request = tx.objectStore(tableName).add(data);
更新数据
同上,创建事务,然后更新数据,如下
const tx = db.transaction([tableName], 'readwrite');
const request = tx.objectStore(tableName).put(data);
获取数据
同上,创建事务,获取数据
const tx = db.transaction([tableName], 'readonly');
const request = tx.objectStore(tableName).get(key);
数据库内保存的数据如下

删除数据
同样的也可以删除数据
const tx = db.transaction([tableName], 'readwrite');
const request = tx.objectStore(tableName).delete(key);
清空数据
const tx = db.transaction([tableName], 'readwrite');
const request = tx.objectStore(tableName).clear();
获取所有数据
也可以通过某一个index获取所有数据,如下
const tx = db.transaction([tableName], 'readonly');
const os = tx.objectStore(tableName);
const index = os.index(indexName);
const request = index.getAll();
【qiao.db.js】
封装了一个npm包,欢迎使用,https://code.insistime.com/#/qiao.db.js
|—封装数据库和表相关操作
|—封装数据相关操作
【实战一个todolist】
之前使用LocalStorage开发了一个todolist,
效果: https://insistime.com/dishi-ls
代码: https://github.com/uikoo9/dishi-monorepo/tree/localstorage
功能比较简单,添加todo,已经点击完成todo,如下

由于LocalStorage不具备数据库特性,
所以像一些排序等操作比较麻烦,
这里使用刚介绍的IndexedDB改造一下
表结构
首先是要设计一个简单的表结构
db_dishi
|-- t_todos
|--create_time
|--todo_content
|--todo_time
|--t_dones
|--done_time
|--todo_content
|--todo_time
其中
数据库:db_dishi
表t_todos:待办列表,create_time作为主键,todo_content内容,todo_time待办时间
表t_dones:完成列表,done_time作为主键,todo_content内容,todo_time待办时间
创建数据库
1.使用listDB方法获取数据列表,判断是否已经创建过数据库
2.使用openDB方法创建数据库
const dbName = 'db_dishi';
// check
const dbs = await listDB();
if (dbs && dbs.length && dbs[0].name == dbName) return;
// db
const db = await openDB(dbName);
创建表
1.使用createTable方法创建表
2.表t_todos
// table
const tableTodos = 't_todos';
const tableDones = 't_dones';
const tables = [
{
name: tableTodos,
key: 'create_time',
index: [
{
name: 'todo_time',
index: ['todo_time', 'todo_content'],
unique: false,
},
],
},
{
name: tableDones,
key: 'done_time',
index: [
{
name: 'done_time',
index: ['done_time'],
unique: false,
},
],
},
];
await createTable(db, tables);
表t_todos:主键为create_time,索引todo_time,按todo_time和todo_content字段做索引
表t_dones:主键为done_time,索引done_time,按done_time字段做索引
创建好数据库和表后,如下

添加数据
1.使用save方法添加数据
// save
const create_time = Date.now();
const data = {
todo_content: todo_content,
todo_time: todo_time || '_',
create_time: create_time,
};
const db = await openDB(dbName);
const saveRes = await save(db, tableName, create_time, data);
console.log('add todo:', saveRes);
添加一些数据后的效果如下,可以看到默认是按主键create_time进行排序的

点击todo_time这个索引,可以看到已经按todo_time和todo_content排序了

获取数据
1.使用getAll方法获取索引todo_time的所有数据
2.这样会默认按索引todo_time的规则返回数据,如上
const res = await getAll(db, tableName, 'todo_time');
console.log(res);
删除数据
1.使用get方法获取todo
2.使用del方法删除todo
// todo
const db = await openDB(dbName);
const todo = await get(db, tableTodos, key);
// done
const done = {
todo_content: todo.todo_content,
todo_time: todo.todo_time,
done_time: Date.now(),
};
const saveRes = await save(db, tableDones, null, done);
// del
await del(db, tableTodos, key);
console.log('del todo:', saveRes);
最终效果
1.添加todo
2.添加todo@20221010,记录待办时间
3.点击todo,完成待办

以上代码见: https://github.com/uikoo9/dishi-monorepo/tree/indexeddb
最终效果见: https://insistime.com/dishi-indexeddb
【总结】
1.IndexedDB介绍
2.IndexedDB和LocalStorage对比
3.IndexedDB数据库和表相关操作
4.IndexedDB数据相关操作
5.IndexedDB封装工具: https://code.insistime.com/#/qiao.db.js
6.IndexedDB实战一个todolist,https://insistime.com/dishi-indexeddb