使用方式
看了上面的代码可能会感觉很晕,这么复杂?不是说很简单吗?
对呀,把复杂封装进去了,剩下的就是简单的调用了。那么如何使用呢?
准备创建数据库的信息
我们先定义一个对象,存放需要的各种信息
const dbInfo = { dbFlag: 'project-meta-db', // 数据库标识,区分不同的数据库。如果项目里只有一个,那么不需要加这个标识 dbConfig: { dbName: 'nf-project-meta', // 数据库名称 ver: 2 }, stores: { // 数据库里的表(对象仓库) moduleMeta: { // 模块的meta {按钮,列表,分页,查询,表单若干} id: 'moduleId', index: {}, isClear: false }, menuMeta: { // 菜单用的meta id: 'id', index: {}, isClear: false }, serviceMeta: { // 后端API的meta,在线演示用。 id: 'moduleId', index: {}, isClear: false } }, init: (help) => { // 数据库建立好了 console.log('inti事件触发:indexedDB 建立完成 ---- help:', help) } }
- dbFlag 一个项目里面可能需要同时使用多个 indexedDB 的数据库,那么就需要一个标识区分一下,dbFlag 就是区分标识。
- stores 对象仓库的说明,在 onupgradeneeded 事件里面依据这个信息创建对象仓库。
- init indexedDB 都准备好之后的回调函数。
直接使用
import IndexedDB from'../../../packages/nf-ws-indexeddb/help.js' // 建立实例 const help = new IndexedDB(dbInfo) // 添加对象的测试 const add = () => { // 定义一个对象 const model = { id: newDate().valueOf(), name: 'test' } // 添加 help.addModel('menuMeta', model).then((res) => { console.log('添加成功!', res) // 返回对象ID }) }
- 定义一个数据库描述信息
- 生成 help 的实例
- 使用 help.addModel 添加对象
做个“外壳”套个娃
检查一下代码,发现有几个小问题:
- 每次使用都需要实例化一个help吗?是不是有点浪费?
- 对象仓库名还需要写字符串,万一写错了怎么办?
- help.xxxModel(xxx,xxx,xxx) 是不是有点麻烦?
所以我们需要在套一个外壳,让使用更方便。
import IndexedDB from'./help.js' /** * 把 indexedDB 的help 做成插件的形式 */ exportdefault { _indexedDBFlag: Symbol('nf-indexedDB-help'), _help: {}, // 访问数据库的实例 _store: {}, // 存放对象,实现 foo.addModel(obj)的功能 createHelp (info) { let indexedDBFlag = this._indexedDBFlag if (typeof info.dbFlag === 'string') { indexedDBFlag = Symbol.for(info.dbFlag) } elseif (typeof info.dbFlag === 'symbol') { indexedDBFlag = info.dbFlag } // 连接数据库,获得实例。 const help = new IndexedDB(info) // 存入静态对象,以便于支持保存多个不同的实例。 this._help[indexedDBFlag] = help // help this._store[indexedDBFlag] = {} // 仓库变对象 // 把仓库变成对象的形式,避免写字符串的仓库名称 for (const key in info.stores) { this._store[indexedDBFlag][key] = { put: (obj) => { let _id = obj if (typeof obj === 'object') { _id = obj[info.stores[key].id] } return help.updateModel(key, obj, _id) }, del: (obj) => { let _id = obj if (typeof obj === 'object') { _id = obj[info.stores[key].id] } return help.deleteModel(key, _id) }, add: (obj) => help.addModel(key, obj), get: (id = null) => help.getModel(key, id) } } }, // 获取静态对象里的数据库实例 useDBHelp (_dbFlag) { let flag = this._indexedDBFlag if (typeof _dbFlag === 'string') { flag = Symbol.for(_dbFlag) } elseif (typeof _dbFlag === 'symbol') { flag = _dbFlag } returnthis._help[flag] }, useStore (_dbFlag) { let flag = this._indexedDBFlag if (typeof _dbFlag === 'string') { flag = Symbol.for(_dbFlag) } elseif (typeof _dbFlag === 'symbol') { flag = _dbFlag } returnthis._store[flag] } }
首先,这是一个静态对象,可以存放 help 的实例,可以实现全局访问的效果。
以前是 使用 provide / inject 保存的,但是发现有点不太方便,也不是十分必要,所以改成了静态对象的方式。
然后根据建表的信息,创建仓库的对象,把字符串的仓库名称变成对象的形式,这样就方便多了。
为啥是 “useDBHelp”呢,因为要和 webSQL的 help 加以区分。
使用的时候就变成了这样:
// 把仓库当做“对象” const { menuMeta } = dbInstall.useStore(dbInfo.dbFlag) // 添加对象 const add = () => { const t1 = window.performance.now() console.log('\n -- 准备添加对象 --:', t1) const model = { id: newDate().valueOf(), name: 'test-。' } menuMeta.add(model).then((res) => { const t2 = window.performance.now() console.log('添加成功!', res, '用时:', t2 - t1, '\n') }) }
这样的话,就方便多了。对象仓库名.xxx(oo)
就可以,代码简洁了很多。
进一步套娃
上面是把对象仓库看做了“对象”,然后实现增删改查,那么能不能让object 本身实现增删改查呢?
既然封装到这一步了,我们可以再前进一下,使用 js的原型 实现 object 的增删改查。
// 给 model 加上增删改查的函数 for (const key in info.stores) { this._store[indexedDBFlag][key] = { createModel: (model) => { function MyModel (_model) { for (const key in _model) { this[key] = _model[key] } } MyModel.prototype.add = function (tran = null) { return help.addModel(key, this, tran) } MyModel.prototype.save = function (tran = null) { const _id = this[info.stores[key].id] return help.setModel(key, this, _id, tran) } MyModel.prototype.load = function (tran = null) { returnnewPromise((resolve, reject) => { // 套个娃 const _id = this[info.stores[key].id] help.getModel(key, _id, tran).then((res) => { Object.assign(this, res) resolve(res) }) }) } MyModel.prototype.del = function (tran = null) { const _id = this[info.stores[key].id] return help.delModel(key, _id, tran) } const re = new MyModel(model) return reactive(re) } } }
首先给对象仓库加一个 “createModel”函数,用于把 object 和对象仓库挂钩,然后用原型挂上增删改查的函数,最后 new 一个实例返回。
使用方式:
// 对象仓库,创建一个实例,reactive 形式 const testModel = menuMeta.createModel({ id: 12345, name: '对象自己save' }) // 对象直接保存 const mSave = () => { testModel.name = '对象自己save' + window.performance.now() testModel.save().then((res) => { // 保存完成 }) }
因为加上了 reactive,所以可以自带响应性。这样是不是很像“充血实体类”了?
id 值建议不要修改,虽然可以改,但是总感觉改了的话比较别扭。
统一“出口”
虽然用 help 带上了几个常规操作,但是出口还是不够统一,像 Vue 那样,就一个出口是不是很方便呢?所以我们也要统一一下:
storage.js
// 引入各种函数,便于做成npm包 // indexedDB 部分 import dbHelp from'./nf-ws-indexeddb/help.js' import dbInstall from'./nf-ws-indexeddb/install.js' // indexedDB 部分 const dbCreateHelp = (info) => dbInstall.createHelp(info) const useDBHelp = (_dbFlag) => dbInstall.useDBHelp(_dbFlag) const useStores = (_dbFlag) => dbInstall.useStores(_dbFlag) export { // indexedDB 部分 dbHelp, // indexedDB 的 help dbCreateHelp, // 创建 help 实例,初始化设置 useDBHelp, // 组件里获取 help 的实例 useStores // 组件里获取对象仓库,方便实现增删改查 }
这样也便于我们打包发布到npm。
在 vue 里面使用
基本工作都作好了,就剩最后一个问题了,在 Vue3 里面如何使用呢?
我们可以仿造一下 vuex 的使用方式,先建立一个 js文件,实现统一设置。
store-project/db.js
// 引入 indexedDB 的 help import { dbCreateHelp } from'../../packages/storage.js' // 引入数据库数据 const db = { dbName: 'nf-project-meta', ver: 5 } /** * 设置 */ exportdefaultfunction setup (callback) { const install = dbCreateHelp({ // dbFlag: 'project-meta-db', dbConfig: db, stores: { // 数据库里的表 moduleMeta: { // 模块的meta {按钮,列表,分页,查询,表单若干} id: 'moduleId', index: {}, isClear: false }, menuMeta: { // 菜单用的meta id: 'id', index: {}, isClear: false }, serviceMeta: { // 后端API的meta,在线演示用。 id: 'moduleId', index: {}, isClear: false }, testIndex: { // 测试索引和查询。 id: 'moduleId', index: { kind: false, type: false }, isClear: false } }, // 加入初始数据 init (help) { if (typeof callback === 'function') { callback(help) } } }) return install }
然后在 main.js 里面调用,因为这是最早执行代码的地方,可以第一时间建立数据库。
// 引入 indexedDB 的help import dbHelp from'./store-project/db.js' dbHelp((help) => { // indexedDB 准备好了 console.log('main里面获取 indexedDB 的help', help) })
同时可以把 help 的实例存入静态对象里面。
其实一开始是使用 provide 注入的,但是发现不是太适合,因为在main.js这个层级里面无法使用inject读取出来,这样的话,和状态等的操作就不太方便。
所以干脆放在静态对象里面好了,任何地方都可以访问到。
并不需要使用 use 挂载到 App 上面。
索引和查询
由于篇幅有限,这里就先不介绍了,如果大家感兴趣的话,可以在写一篇补充一下。
源码
封装前端存储https://gitee.com/naturefw/nf-web-storage
在线演示
https://naturefw.gitee.io/vite2-vue3-demo
安装方式
yarn add nf-web-storage
本文作者:自然框架
个人网址:jyk.cnblogs.com
声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。