封装 indexedDB(三)写个插件

因为要在 vue 里面使用,所以做个插件可以方便很多。

项目需求

  • 第一次访问,初始化,需要建立表、导入初始数据
  • 组件获取需要的数据
  • 数据更新的问题

插件功能

  • 在 main 里面安装插件。
  • 建立一个 help, 用 provide 保存,以便于其他组件使用。

定义结构

我们需要先定义一下结构:

{
  dbConfig: db, // 连接字符串,库名和版本
  stores: { // 数据库里的表的集合
    moduleMeta: { // 对象仓库名称
      id: 'moduleId', // keyPath 的名称
      index: {}, // 设置所以
      isClear: false // 是否清空数据
    }
  },
  init (help) {
    // 导入初始数据
  }
  • dbConfig
    设置库名称和版本号

  • stores
    对象仓库的集合,每个属性就是一个对象仓库,依据属性创建对象仓库。

  • init
    传递一个help过来,可以添加数据。

实现插件


import { inject } from 'vue'

import IndexedDB from './help.js'

export default {
  _indexedDBFlag: Symbol('nf-indexedDB-help'),
  _help: {}, // 访问数据库的实例

  /**
   * 根据参数创建一个数据库的实例,初始化数据库
   * * 删表、建表、添加默认数据
   * @param {*} info 参数
   * @returns 安装一个Vue的插件
   * * dbFlag: '数据库标识',
   * * dbConfig: { // 连接数据库
   * * *  dbName: 'vite2-blog',
   * * *  ver: 1.0
   * * },
   * * init: () => {},
   * * stores: {
   * * * storeName: { // 表名
   * * * * id: 'id', // 主键名称
   * * * * index: {
   * * * * * name: ture, // 索引:是否可以重复
   * * * * },
   * * * * isDeleteOldTable: false, // 是否删除之前的表
   * * * }
   * * }
   */
  createHelp (info) {
    let indexedDBFlag = this._indexedDBFlag
    if (typeof info.dbFlag === 'string') {
      indexedDBFlag = Symbol.for(info.dbFlag)
    }
    if (typeof info.dbFlag === 'symbol') {
      indexedDBFlag = info.dbFlag
    }
    // 连接数据库
    const help = new IndexedDB(info)

    return {
      // 安装插件
      install (app, options) {
        // 注入状态,用 symbol 作为标记,避免重名
        app.provide(indexedDBFlag, help)
      }
    }
  },

  // 代码里面调用
  useHelp (_dbFlag) {
    let flag = this._indexedDBFlag
    if (typeof _dbFlag === 'string') {
      flag = Symbol.for(_dbFlag)
    }
    if (typeof _dbFlag === 'symbol') {
      flag = _dbFlag
    }
    if (typeof inject(flag) === 'undefined') {
      // 根级调用
      return this._help
    } else {
      // 子组件调用
      const help = inject(flag)
      return help
    }
  }
}

  • _indexedDBFlag
    Symbol 类型的标识,区分不同的数据库。

  • createHelp
    创建一个 vue 的插件。这里基本没啥代码,就是做个help,然后用 provide 注入一下以便于其他组件也可以使用。
    主要代码还是在 help 的 onupgradeneeded 实现的,这个我也没想到更好的办法。

  • useHelp
    子组件里面获取 help,然后使用这个 help 就可以对 indexedDB 进行操作了。

为啥要弄个 help ?因为想更好的控制初始化和组件读取数据的先后关系。

建库与升级

因为 indexedDB 在初始化的时候会触发 onupgradeneeded ,所以一些代码还是要写在这里。

onupgradeneeded

    // 根据配置信息建立表
    this.dbRequest.onupgradeneeded = (event) => {
      this._dataState = 'loading' // 需要加载
      const db = event.target.result
      console.log('【2】升级数据库 onupgradeneeded --- ', db)

      for (const key in info.stores) {
        const store = info.stores[key]
        // 验证有没有表,没有的话建立一个对象表
        if (!db.objectStoreNames.contains(key)) {
          // const objectStore = db.createObjectStore(object.objectStoreName, { keyPath: 'id' }) /* 创建person仓库(表) 主键 */
          const objectStore = db.createObjectStore(key, { keyPath: store.id }) /* 自动创建主键 autoIncrement: true */
          // 建立索引
          for (const key2 in store.index) {
            const unique = store.index[key2]
            objectStore.createIndex(key2, key2, { unique: unique })
          }
          // if (config.debug) {
          console.log('onupgradeneeded - 建立了一个新的对象仓库:', key)
          // }
        }
      }
    }
    // 根据配置信息建立表
    this.dbRequest.onerror = (event) => {
      // 出错
      console.log('打开数据库出错:', event.target.error)
    }
  }

一开始想在这里添加初始数据的,但是实验了一下发现不行,因为这时候还是“建库”状态,不让填数据。
所以只好把填数据的操作放在 onsuccess 里面。

onsuccess

    // 打开成功,记录连接对象
    this.dbRequest.onsuccess = (event) => {
      this._db = event.target.result
      if (this._dataState === 'none') return

      if (this._dataState === 'loading') {
        // 升级后需要添加初始数据
        if (typeof info.init !== 'function') {
          this._dataState = 'none'
          // 没有设置添加初始化数据的函数
          return
        }

        if (typeof info.init === 'function') {
          // 调用填数据的函数,传入help
          info.init(this)
        }
      }
    }

beginInit

然后我又偷偷的做了一个专门的事务。

  // 初始化填数据的事务
  beginInit (storeName) {
    return new Promise((resolve, reject) => {
      //
      const tranRequest = this._db.transaction(storeName, 'readwrite')
      const store = tranRequest.objectStore(storeName) // 获取store

      tranRequest.onerror = (event) => {
         console.log('读写事务出错:', event.target.error)
         reject('读写事务出错:' + event.target.error)
         tranRequest.abort()
      }

      tranRequest.oncomplete = (event) => {
        // 事务执行完毕
        this._dataState = 'none'
      }
      // 返回对象仓库
      resolve(store)
    })
  }

开启一个读写事务,然后打开对象仓库,把仓库返回去。然后调用者就可以用这个仓库添加对象了。

然后在 oncomplete 里面设置状态。这样就都联系起来了。
好吧有点绕。很容易晕。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容