乐趣区

关于前端:用IndexedDB保存并导出前端日志TS版适用原生JSVue和React

环境

  • Windows 10
  • Node.js v18.0.0
  • Yarn (用 npmpnpm也没问题)
  • VS Code
  • Chrome

前言

  • 本教程间接给出办法,复制即可用。须要肯定的 indexedDB 的基础知识
  • 办法中并没有应用异步,依据须要自行添加即可
  • 尽管本教程给只出了 VueReact两个 JS 框架的例子,然而其中函数也能够间接用于原生 TS 和 JS

装置第三方库

  • file-saver:导出文件用,@types/file-saver是他的类型库
  • dayjs:工夫库,能够依据集体爱好抉择其余工夫库
yarn add -D file-saver @types/file-saver dayjs

Vue.js 版本

App.vue

<script setup lang="ts">
// 导入第三方库
import dayjs from "dayjs";
import {saveAs} from "file-saver";
​
// 定义常量
const dataBaseVer: number = 1; // 版本
const dataBaseName: string = "MyIndexedDB"; // db 名
const dataBaseStore: string = "MyStore"; // store 名
const dataBaseKeyPath: string = "key"; // 主 key
const dataBaseLimit: number = 10000; // 数据条数限度
const filename: string = `log_${dayjs().format("YYYYMMDD")}.txt`; // 导出的 log 文件名
​
// 创立 indexedDB
const createIndexedDB = (): void => {const indexed: IDBOpenDBRequest = indexedDB.open(dataBaseName, dataBaseVer);
​
  // 第一次执行,因为没有版本,所以会触发 onupgradeneeded 事件,此时新建 store 并追加主 key
  indexed.onupgradeneeded = (event: IDBVersionChangeEvent): void => {const db: IDBDatabase = (event.target as IDBOpenDBRequest).result;
    if (!db.objectStoreNames.contains(dataBaseStore)) {
      db.createObjectStore(dataBaseStore, {keyPath: dataBaseKeyPath,});
    }
  };
​
  // 创立失败
  indexed.onerror = (): void => {console.log("Indexed Start Error");
  };
};
​
// 增加 log
const addLog = (log: string): void => {
  // 获取 log 工夫戳
  const time = dayjs().format("YYYY-MM-DD-HH:mm:ss:SSS");
  const random = Math.ceil(Math.random() * 999);
  const timeStamp = time + "_" + random + "Z";
​
  // 关上 db
  const indexed: IDBOpenDBRequest = indexedDB.open(dataBaseName);
  indexed.onsuccess = (event: Event): void => {const db: IDBDatabase = (event.target as IDBOpenDBRequest).result;
    const trans: IDBTransaction = db.transaction(dataBaseStore, "readwrite");
    const store: IDBObjectStore = trans.objectStore(dataBaseStore);
    const count: IDBRequest<number> = store.count();
​
    // 计算记录的数量,增加前先查看是否超过限度
    count.onsuccess = (): void => {
      // 没超过就增加
      if (Number(count.result) <= dataBaseLimit) {
        // 以主键 log 为 key,把工夫戳和 log 作为 value,插入数据库
        store.put({[dataBaseKeyPath]: `[${timeStamp}] : ${log}` });
        return;
      } else {
        // 没超过就删除最老的一条
        store.openCursor().onsuccess = (event: Event): void => {const cursor: any = (event.target as IDBRequest).result;
          if (cursor) {cursor.delete();
          }
        };
      }
    };
​
    // 计算记录的数量失败
    count.onerror = (): void => {console.log("Count Error");
    };
  };
​
  // db 关上失败
  indexed.onerror = (): void => {console.log("Indexed Open Error");
  };
};
​
// 读取 log
const readDBandExport = (): void => {let tmp: string[] = [];
​
  // 关上 db
  const indexed: IDBOpenDBRequest = indexedDB.open(dataBaseName);
  indexed.onsuccess = (event: Event): void => {const db: IDBDatabase = (event.target as IDBOpenDBRequest).result;
    const trans: IDBTransaction = db.transaction(dataBaseStore, "readonly");
    const store: IDBObjectStore = trans.objectStore(dataBaseStore);
​
    // 遍历数据
    store.openCursor().onsuccess = (event: Event): void => {const cursor: any = (event.target as IDBRequest).result;
      // 如果遍历项有数据就放入 tmp,而后持续
      if (cursor) {tmp.push(cursor.key);
        tmp.push("\r\n");
        cursor.continue();} else {
        // 如果遍历项没有数据,阐明遍历完结,这时新建 blob 对象
        const blob: Blob = new Blob(tmp, {type: "text/plain;charset=utf-8",});
​
        // 导出文件
        saveAs(blob, filename);
      }
    };
​
    // 遍历数据失败
    store.openCursor().onerror = (): void => {console.log("OpenCursor Error");
    };
  };
​
  // db 关上失败
  indexed.onerror = (): void => {console.log("Indexed Open Error");
  };
};
​
// 删除数据库
const deleteIndexedDB = (): void => {const indexed: IDBOpenDBRequest = indexedDB.deleteDatabase(dataBaseName);
​
  // 删除胜利
  indexed.onsuccess = (): void => {console.log("Delete Success");
  };
​
  // 删除失败
  indexed.onerror = (): void => {console.log("Delete Error");
  };
};
​
// 调用
createIndexedDB();
// 测试
addLog("テスト");
</script>
​
<template>
  <main>
    <h1>Vue.js</h1>
    <button @click="addLog(' ボタンからのテスト ')">addLog</button>
    <button @click="readDBandExport">readDBandExport</button>
    <button @click="deleteIndexedDB">deleteIndexedDB</button>
  </main>
</template>

React.js 版本

App.tsx

// 导入第三方库
import dayjs from "dayjs";
import {saveAs} from "file-saver";
​
function App() {
  // 定义常量
  const dataBaseVer: number = 1; // 版本
  const dataBaseName: string = "MyIndexedDB"; // db 名
  const dataBaseStore: string = "MyStore"; // store 名
  const dataBaseKeyPath: string = "key"; // 主 key
  const dataBaseLimit: number = 10000; // 数据条数限度
  const filename: string = `log_${dayjs().format("YYYYMMDD")}.txt`; // 导出的 log 文件名
​
  // 创立 indexedDB
  const createIndexedDB = (): void => {const indexed: IDBOpenDBRequest = indexedDB.open(dataBaseName, dataBaseVer);
​
    // 第一次执行,因为没有版本,所以会触发 onupgradeneeded 事件,此时新建 store 并追加主 key
    indexed.onupgradeneeded = (event: IDBVersionChangeEvent): void => {const db: IDBDatabase = (event.target as IDBOpenDBRequest).result;
      if (!db.objectStoreNames.contains(dataBaseStore)) {
        db.createObjectStore(dataBaseStore, {keyPath: dataBaseKeyPath,});
      }
    };
​
    // 创立失败
    indexed.onerror = (): void => {console.log("Indexed Start Error");
    };
  };
​
  // 增加 log
  const addLog = (log: string): void => {
    // 获取 log 工夫戳
    const time = dayjs().format("YYYY-MM-DD-HH:mm:ss:SSS");
    const random = Math.ceil(Math.random() * 999);
    const timeStamp = time + "_" + random + "Z";
​
    // 关上 db
    const indexed: IDBOpenDBRequest = indexedDB.open(dataBaseName);
    indexed.onsuccess = (event: Event): void => {const db: IDBDatabase = (event.target as IDBOpenDBRequest).result;
      const trans: IDBTransaction = db.transaction(dataBaseStore, "readwrite");
      const store: IDBObjectStore = trans.objectStore(dataBaseStore);
      const count: IDBRequest<number> = store.count();
​
      // 计算记录的数量,增加前先查看是否超过限度
      count.onsuccess = (): void => {
        // 没超过就增加
        if (Number(count.result) <= dataBaseLimit) {
          // 以主键 log 为 key,把工夫戳和 log 作为 value,插入数据库
          store.put({[dataBaseKeyPath]: `[${timeStamp}] : ${log}` });
          return;
        } else {
          // 没超过就删除最老的一条
          store.openCursor().onsuccess = (event: Event): void => {const cursor: any = (event.target as IDBRequest).result;
            if (cursor) {cursor.delete();
            }
          };
        }
      };
​
      // 计算记录的数量失败
      count.onerror = (): void => {console.log("Count Error");
      };
    };
​
    // db 关上失败
    indexed.onerror = (): void => {console.log("Indexed Open Error");
    };
  };
​
  // 读取 log
  const readDBandExport = (): void => {let tmp: string[] = [];
​
    // 关上 db
    const indexed: IDBOpenDBRequest = indexedDB.open(dataBaseName);
    indexed.onsuccess = (event: Event): void => {const db: IDBDatabase = (event.target as IDBOpenDBRequest).result;
      const trans: IDBTransaction = db.transaction(dataBaseStore, "readonly");
      const store: IDBObjectStore = trans.objectStore(dataBaseStore);
​
      // 遍历数据
      store.openCursor().onsuccess = (event: Event): void => {const cursor: any = (event.target as IDBRequest).result;
        // 如果遍历项有数据就放入 tmp,而后持续
        if (cursor) {tmp.push(cursor.key);
          tmp.push("\r\n");
          cursor.continue();} else {
          // 如果遍历项没有数据,阐明遍历完结,这时新建 blob 对象
          const blob: Blob = new Blob(tmp, {type: "text/plain;charset=utf-8",});
​
          // 导出文件
          saveAs(blob, filename);
        }
      };
​
      // 遍历数据失败
      store.openCursor().onerror = (): void => {console.log("OpenCursor Error");
      };
    };
​
    // db 关上失败
    indexed.onerror = (): void => {console.log("Indexed Open Error");
    };
  };
​
  // 删除数据库
  const deleteIndexedDB = (): void => {const indexed: IDBOpenDBRequest = indexedDB.deleteDatabase(dataBaseName);
​
    // 删除胜利
    indexed.onsuccess = (): void => {console.log("Delete Success");
    };
​
    // 删除失败
    indexed.onerror = (): void => {console.log("Delete Error");
    };
  };
​
  // 调用
  createIndexedDB();
  // 测试
  addLog("テスト");
​
  return (
    <main>
      <h1>React.js</h1>
      <button onClick={() => {addLog("ボタンからのテスト");}}>
          addLog
      </button>
      <button onClick={readDBandExport}>readDBandExport</button>
      <button onClick={deleteIndexedDB}>deleteIndexedDB</button>
    </main>
  );
}
​
export default App;

验证(以 Vue.js 为例)

启动我的项目后,发现数据库曾经建设

点击 addLog 增加测试数据,而后按 readDBandExport 导出

查看导出的文件,胜利

最初

如果须要联合捕捉 console.log 应用,请应用上面的函数

// log 捕捉
const catchConsoleLog = () => {
  console.oldLog = console.log;
​
  console.log = (log: string) => {
    // 打印捕捉的 log
    console.oldLog(log);
    addLog(log);
  };
};
​
// 应用
catchConsoleLog()
退出移动版