索引数据库,操作简便(目前主流浏览器正努力实现对index DB的支持),最主要的是我们可以很轻松的通过JS极其方便的对其调用;
现今多数业务需要离线访问、或将大量数据储存在客户端,减少从服务器获取数据,直接从本地获取数据。
目前做的业务中需要将图片及其他数据存储在本地、在有网时将其发送给服务器;考虑到手机图片过大、localStorage存储大小限制为5M、所以对indexDB做一封装、以便往后不再需要研究其中api、直接copy文件、调用其中方法;;
本以为会有能说清楚的博客、发现大家都在自己的业务层面苦苦挣扎、代码也是不清不楚、乱如麻,自己将代码整理了一番。
以下源码已封装、发到npm仓库,直接下载promise-indexeddb npm 包;
npm install promise-indexeddb --save
拷贝promise-indexeddb包下的index.js 到自己的项目目录中、更换为自己想改的名称;
import * as IndexedDB from '@/utils/indexedDB';
IndexedDB.init({
// 数据库名称
dbName: 'hantMobile',
// 数据表 数组 如果要创建多个表,则写多个即可
tableList: [
{
// 表名
tableName: 'patrolTable',
// 主键
keyPath: 'name',
// 对应表的其他属性
// attr:{
// autoIncrement:true, //是否自增
// },
// indexName: 'index',// 索引 不建议使用 因为使用索引 当前表必须有数据否则直接报错
// unique:false // 对应索引是否唯一
},
],
})
执行以上操作之后可以查看浏览器已为我们创建了对应的数据库和表
await IndexedDB.add({
// 加到那个表里
tableName: 'patrolTable',
// data是要添加的数据
data: {
// 伪代码
// 对应的主键与值 此处主键为name 主键值为file.name
name: file.name,
// 数据
baseData: result,
},
})
此时有同学发现对应的表下还是没有数据、indexedDB和localStorage不一样,不会实时刷新的、需要点到indexedDB上右键点击 refresh
const result = await IndexedDB.readAll('patrolTable');
console.log('result--->',result);
const dbRes = await IndexedDB.readByMainKey({
// 表名
tableName: 'patrolTable',
// 主键值
key: '1',
})
const dbRes = await IndexedDB.readByIndex({
// 表名
tableName: 'patrolTable',
// 索引名
indexName: 'name',
// 索引值
indexVal: '文杰'
})
IndexedDB.update({
// 表名
tableName: patrolListTable.name,
// 对应的主键与值 和 数据 此处主键为userId 主键值为id
data: {
userId: '1',
patrolList: [{ name: '文杰' }],
},
})
IndexedDB.remove({
tableName: 'patrolTable',
key: '1',
})
IndexedDB.deleteDB('hantMobile')
IndexedDB.deleteDB('hantMobile')
IndexedDB.deleteDB('patrolTable')
以下为封装的indexDB代码
let db;
let openRequest;
const indexedDB =
window.indexedDB ||
window.webkitIndexedDb ||
window.mozIndexed ||
window.msIndexedDB;
// transaction 事务处理 意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
// tableList [{tableName,keyPath,indexName}]
/**
* 初始化数据库
* @param {string} dbName 数据库名
* @param {Array} tableList 数据表列表
*/
// 初始化
export function init({ dbName, tableList }) {
// 存在就打开 不存在新建 第二个参数为db 版本
openRequest = indexedDB.open(dbName);
// 新的数据库创建 或者数据库的版本号被更改会被触发
openRequest.onupgradeneeded = function (e) {
// 表的创建在这个回调里执行
const thisDb = e.target.result;
console.log('running onupgradeneeded' + thisDb);
if (tableList?.length) {
tableList.forEach((table) => {
if (!thisDb.objectStoreNames.contains(table.tableName)) {
console.log('I need to create the objectStore');
// keyPath 主键 autoIncrement 是否自增
const objectStore = thisDb.createObjectStore(table.tableName, {
keyPath: table.keyPath,
...table.attr,
// autoIncrement: true,
});
if (table.indexName) {
// 创建表的时候 可以去指定那些字段是可以被索引的字段
objectStore.createIndex(table.indexName, table.indexName, {
unique: table.unique || false,
});
}
}
});
} else {
console.error('请传入数据表参数');
}
};
// 已经创建好的数据库创建成功的时候
openRequest.onsuccess = function (e) {
db = e.target.result;
db.onerror = function (event) {
console.error('Database error: ' + event.target.errorCode);
console.dir(event.target);
};
};
// 打开失败时调用
openRequest.onerror = function (e) {
console.error('openRequest.onerror', e);
};
}
/**
* 添加一行
* @param {string} tableName 表名
* @param {object} data 数据
* @returns {promise}
*/
export function add({ tableName, data }) {
return new Promise((suc, fail) => {
const request = db
.transaction([tableName], 'readwrite')
.objectStore(tableName)
.add(data);
request.onsuccess = function (event) {
suc();
console.log('数据写入成功', event);
};
request.onerror = function (event) {
fail();
console.log('数据写入失败', event);
};
});
}
/**
* 遍历所有数据 其实这里有点坑 真正readAll是下面readAllPC这个方法,因为低版本webview手机不兼容objectStore.getAll所以使用游标来实现
* @param {string} tableName 表名
* @returns {promise}
*/
export function readAll(tableName) {
return new Promise((suc, fail) => {
const objectStore = db
.transaction([tableName], 'readwrite')
.objectStore(tableName);
// 我这里做的是把所有的结果全部收集起来 当然我们可以做其他事情此处拿到的value是每条数据的结果、还有primaryKey主键、key、与direction
const result = [];
objectStore.openCursor().onsuccess = function (event) {
const cursor = event.target.result;
if (cursor) {
result.push({ ...cursor.value });
cursor.continue();
} else {
suc(result);
console.log('readAll成功==>' + result);
}
};
objectStore.openCursor().onerror = function (event) {
console.dir(event);
fail();
};
});
}
/**
* 读取所有数据 仅在pc上或者版本高的手机浏览器中使用 readAllPC这个方法 这个在低版本weview的手机浏览器里面不兼容
* @param {string} tableName
* @returns {promise}
*/
export function readAllForHighVersion(tableName) {
return new Promise((suc, fail) => {
const objectStore = db
.transaction([tableName], 'readwrite')
.objectStore(tableName);
const request = objectStore.getAll();
request.onerror = function (event) {
fail();
console.log('readAll--->读取表事务失败', event);
};
request.onsuccess = function () {
suc(request.result || []);
};
});
}
/**
* 根据主键查询对应数据
* @param {string} tableName 表名
* @param {string} key 主键
* @returns {promise}
*/
export function readByMainKey({ tableName, key }) {
return new Promise((suc, fail) => {
if (!key) {
fail();
return;
}
const objectStore = db
.transaction([tableName], 'readwrite')
.objectStore(tableName);
const request = objectStore.get(key);
request.onerror = function (event) {
console.error('根据主键查询对应数据', event);
fail();
};
request.onsuccess = function () {
suc(request.result || {});
};
});
}
/**
* 根据主键删除对应数据
* @param {string} tableName 表名
* @param {string} key 主键
* @returns {promise}
*/
export function remove({ tableName, key }) {
return new Promise((suc, fail) => {
const objectStore = db
.transaction([tableName], 'readwrite')
.objectStore(tableName);
const request = objectStore.delete(key);
request.onerror = function (event) {
console.error('更新失败', event);
fail();
};
request.onsuccess = function (event) {
console.log('删除成功', event);
suc();
};
});
}
/**
* 根据主键更新对应数据
* @param {object} data 对应的主键与值 和 数据
* @param {string} tableName 表名
* @returns {promise}
*/
export function update({ tableName, data }) {
return new Promise((suc, fail) => {
const objectStore = db
.transaction([tableName], 'readwrite')
.objectStore(tableName);
const request = objectStore.put(data);
request.onerror = function (event) {
console.error('更新失败', event);
fail();
};
request.onsuccess = function (event) {
console.log('更新成功', event);
suc();
};
});
}
/**
* 通过索引查找对应数据
* @param {string} indexName 索引名称
* @param {any} indexVal index 索引值
* @param {string} tableName 表名
* @returns {promise}
*/
export function readByIndex({ tableName, indexName, indexVal }) {
return new Promise((suc, fail) => {
const objectStore = db
.transaction([tableName], 'readwrite')
.objectStore(tableName);
// 假定新建表格的时候,对name字段建立了索引。
// objectStore.createIndex('name', 'name', { unique: false });
const index = objectStore.index(indexName);
const request = index.get(indexVal);
request.onerror = function (event) {
console.log('事务失败', event);
fail();
};
request.onsuccess = function (event) {
if (request.result) {
suc(request.result);
} else {
console.log('未获得数据记录', event);
}
};
});
}
/**
* 删除数据库
* @param {string} DB_NAME 数据库名称
* @returns
*/
export async function deleteDB(DB_NAME) {
return indexedDB.deleteDatabase(DB_NAME);
}
/**
* 关闭数据库
* @param {string} DB_NAME 数据库名称
* @returns
*/
export function closeDB(DB_NAME) {
return indexedDB.close(DB_NAME);
}
/**
* 清除表
* @param {string} tableName
* @returns {promise}
*/
export function clearTable(tableName) {
return new Promise((suc, fail) => {
const objectStore = db
.transaction([tableName], 'readwrite')
.objectStore(tableName);
const request = objectStore.clear();
request.onerror = function (event) {
console.log('事务失败', event);
fail();
};
request.onsuccess = function (event) {
console.log('清除成功', event);
suc();
};
});
}