svg编辑器——本地持久化存储

182 阅读2分钟

indexdb简介

indexdb是一种浏览器本地化存储,与之功能类似的有cookie(4k),localstorage(5M-10M)。 但是indexdb的存储空间更大,是一种非关系型的本地数据库。

项目中需要对用户所绘制的path路径进行存储,以便下次访问时直接读取渲染在页面上,考虑到存储空间大小的问题,所以选择了indexdb进行存储。

indexdb的优点如下:

1IndexedDB顾名思义是一种内置在浏览器中数据库,而且是一种非关系型的数据库,即不需要编写SQL语句去操作数据库,而且存储的数据格式是JSON2IndexedDB不像我们平时服务器上使用的 NoSQL 数据库,IndexedDB没有表的概念,在IndexedDB中是叫object store,其实平时就可以把object store看做数据表。

3IndexedDB的每次操作都是一个事务,每一个对数据库操作是在一个事务的上下文中执行的。

4IndexedDB的每次数据库操作都需要先打开object store,再执行指定的操作,不能一直打开某个object store。

5IndexedDB的所有操作都是异步的。

indexdb的封装

数据库的基本信息

    private dbName: string = 'svgData';//数据库名称
    private version: number = 1;//数据库版本
    private tableName: string = 'svgPath';//数据表名称
    private db: IDBDatabase | null = null;

数据库的打开 创建数据表

 openDB = () => {
        return new Promise((resolve,reject)=>{
            const request = window.indexedDB.open(this.dbName, this.version);

            request.onsuccess = (event: any) => {//数据库打开成功
                console.log('成功打开数据库')
                this.db = event.target.result
                resolve(1);
            };
    
            request.onupgradeneeded = (event:any) => {
                console.log('成功新建数据库')
                this.db = event.target.result;
                this.create_table(this.db);
            }
    
            request.onerror = (event:any) => {
                console.log('数据库打开报错');
                reject(1);
            };
        })
        
    }

    //新建数据表
    create_table  = (idb: any) => {
        if (!idb.objectStoreNames.contains(this.tableName)) {
            let objectStore;
            objectStore = idb.createObjectStore(this.tableName, { keyPath: 'id' });
            objectStore.createIndex('id', 'id', { unique: true });
        }
    }

读取所有数据(使用游标来进行遍历)

 readAll = () => {
            return new Promise((resolve,reject)=>{
                if(this.db){
                    let objectStore = this.db.transaction(this.tableName).objectStore(this.tableName);
                    objectStore.openCursor().onsuccess = function (event:any) {
                        var cursor = event.target.result;
                        if (cursor) {
                            UIStore.initPathList(cursor.key,cursor.value);
                            cursor.continue();
                        } else {
                            console.log('没有更多数据了!');
                            resolve(1);
                        }
                    };
                }
                else{
                    reject();
                }
            })
    }

增加数据

add  = (newPath:any) => {
        if(this.db){
            let path = toJS(newPath);
            let request = this.db.transaction([this.tableName], 'readwrite')
            .objectStore(this.tableName)
            .add(path);
            request.onsuccess = function (event:any) {
                console.log('数据写入成功');
            };
    
            request.onerror = function (event:any) {
                console.log('数据写入失败'+event);
            }
        } 
    }

更新数据

因为项目中数据更新的频率很高,所以给indexdb的数据更新进行了防抖处理

update = _.debounce((newPath:any)=> {
        if(this.db){
            let path = toJS(newPath);
            let request = this.db.transaction([this.tableName], 'readwrite')
            .objectStore(this.tableName)
            .put(path);
            request.onsuccess = function (event:any) {
                console.log('数据更新成功');
            };

            request.onerror = function (event:any) {
                console.log('数据更新失败');
            }
        }
    },1000,{ 'maxWait': 10000 })

删除数据

 remove = (id:number) => {
        if(this.db){
            let request = this.db.transaction([this.tableName], 'readwrite')
            .objectStore(this.tableName)
            .delete(id);
          request.onsuccess = function (event) {
            console.log('数据删除成功');
          };
        }
    }

在界面初始化时加载数据

 useEffect(() => {
    const initPathList = async() =>{
      try{
        await myIndexDB.openDB();
        await myIndexDB.readAll();
        setNode({ posX: -1, posY: -1, ctrPosX: -1, ctrPosY: -1});//加载结束后重新渲染页面
        console.log('加载数据结束');
      }catch(err){
        console.log('加载失败');
      }
    }
    initPathList();
  }, [])