Stories

Detail Return Return

Web前端入門第 85 問:JavaScript 一個簡單的 IndexedDB 數據庫入門示例 - Stories Detail

在前端風風雨雨的混了多年,從沒在項目中實際使用過 IndexedDB 這個瀏覽器端的數據庫,所以今天就摸了下 MDN 的後門,寫一個簡單的入門示例。

頁面大概長這樣:

85-1

源碼:

以下代碼包含了一個數據庫所有的 CRUD (增刪改查)操作。

<div>
  <button id="js_add_btn">添加書籍</button>
</div>
<div>
  <input type="text" name="" id="js_book_id" placeholder="輸入書籍ID"/>
  <button id="js_get_by_id_btn">查詢書籍</button>
  <button id="js_update_by_id_btn">更新書籍</button>
  <button id="js_delete_by_id_btn">刪除書籍</button>
</div>
<div>
  <input type="text" name="" id="js_book_author" placeholder="輸入書籍作者查詢"/><button id="js_get_by_author_btn">查詢書籍</button>
</div>
<div>
  <button id="js_get_all_btn">查詢所有書籍</button>
</div>
<div id="output"></div>

<script>
  (() => {
    // 數據庫配置
    const dbName = 'MyDB';
    const storeName = 'books';
    const output = document.getElementById('output')
    let db = null;

    function setOutputContent(html) {
      output.innerText = html;
    }

    // 初始化數據庫
    const initDB = () => {
      const request = indexedDB.open(dbName);

      // 數據庫升級/創建時觸發
      request.onupgradeneeded = (event) => {
        db = event.target.result;

        // 創建對象存儲空間(類似數據庫表)
        const store = db.createObjectStore(storeName, {
          keyPath: 'id', // 主鍵
          autoIncrement: true, // 自動生成ID
        });

        // 創建索引(允許通過作者查詢)
        store.createIndex('author_idx', 'author', { unique: false });

        console.log('數據庫已創建/升級');
      };

      // 數據庫打開成功
      request.onsuccess = (event) => {
        db = event.target.result;
        console.log('數據庫已打開');
      };

      // 數據庫打開失敗
      request.onerror = (event) => {
        console.error('數據庫錯誤:', event.target.error);
        setOutputContent('數據庫錯誤');
      };
    };

    // 封裝包裝函數,用於執行數據庫相關方法
    function wrapper(func) {
      return new Promise((resolve, reject) => {
        const transaction = db.transaction([storeName], 'readwrite');
        const store = transaction.objectStore(storeName);
        const res = func(store)
        res.onsuccess = () => {
          resolve(res.result)
        };

        res.onerror = (event) => {
          reject(event.target.error)
        };
      });
    }

    // 添加數據
    const addBook = async (book) => {
      try {
        const result = await wrapper((store) => store.add(book))
        console.log(result);
        setOutputContent(`添加成功!書籍ID: ${result}`);
      } catch (error) {
        console.error(error);
        setOutputContent('添加失敗');
      }
    };

    // 通過ID查詢數據
    const getBook = async (id) => {
      try {
        const book = await wrapper((store) => store.get(id))
        if (book) {
          console.log('查詢結果:', book);
          setOutputContent(`書名: ${book.title}\n作者: ${book.author}\n價格: $${book.price}`);
        } else {
          console.log('未找到書籍');
          setOutputContent('未找到該書籍');
        }
      } catch (error) {
        console.error(error);
        setOutputContent('查詢失敗');
      }
    };

    // 查詢全部數據
    const getAllBook = async () => {
      try {
        const book = await wrapper((store) => store.getAll())
        if (book) {
          console.log('查詢結果:', book);
          setOutputContent(`總數:${book.length}`);
        } else {
          console.log('未找到書籍');
          setOutputContent('未找到該書籍');
        }
      } catch (error) {
        console.error(error);
        setOutputContent('查詢失敗');
      }
    };

    // 更新數據--數據不存在時會添加數據
    const updateBook = async (book) => {
      try {
        const result = await wrapper((store) => store.put(book))
        console.log(result);
        setOutputContent(`更新成功!結果: ${result}`);
      } catch (error) {
        console.error(error);
        setOutputContent('更新失敗');
      }
    };

    // 刪除數據
    const deleteBook = async (id) => {
      try {
        const result = await wrapper((store) => store.delete(id))
        console.log(result);
        setOutputContent(`刪除成功!結果: ${result}`);
      } catch (error) {
        console.error(error);
        setOutputContent('刪除失敗');
      }
    };
    // 根據作者查詢
    const getByAuthor = async (author) => {
      try {
        const result = await wrapper((store) => {
          const index = store.index("author_idx");
          const request = index.getAll(author);
          return request;
        })
        console.log(result);
        setOutputContent(`查詢成功!結果: ${JSON.stringify(result)}`);
      } catch (error) {
        console.error(error);
        setOutputContent('查詢失敗');
      }
    };

    // 添加書籍
    document.getElementById('js_add_btn').onclick = () => {
      addBook({
        title: 'Web前端入門',
        author: '前端路引',
        price: (0.99 * Math.random() + 10) .toFixed(2),
      });
    };

    // 根據ID查詢
    document.getElementById('js_get_by_id_btn').onclick = () => {
      const bookId = document.getElementById('js_book_id').value;
      getBook(Number(bookId));
    };

    // 根據ID刪除
    document.getElementById('js_delete_by_id_btn').onclick = () => {
      const bookId = document.getElementById('js_book_id').value;
      deleteBook(Number(bookId));
    };

    // 根據ID更新
    document.getElementById('js_update_by_id_btn').onclick = () => {
      const bookId = document.getElementById('js_book_id').value;
      updateBook({
        // 主鍵ID
        id: Number(bookId),
        title: 'Web前端入門',
        author: '公眾號:前端路引',
        price: (0.99 * Math.random() + 10) .toFixed(2),
      });
    };

    // 根據作者查詢
    document.getElementById('js_get_by_author_btn').onclick = () => {
      const author = document.getElementById('js_book_author').value
      getByAuthor(author);
    };

    // 查詢全部
    document.getElementById('js_get_all_btn').onclick = () => {
      getAllBook();
    };

    // 頁面加載時初始化數據庫
    initDB();
  })();
</script>

IndexedDB 大小限制

以下內容為 AI 回答:

85-2

獲取可用的存儲空間大小

navigator.storage.estimate().then((estimate) => {
  console.log(
    `已使用:`,
    (
      (estimate.usage / estimate.quota) * 100
    ).toFixed(2)
  );
  console.log(`可使用:`, (estimate.quota / 1024 / 1024).toFixed(2) + "MB");
});

相關文檔:https://developer.mozilla.org/en-US/docs/Web/API/Storage_API

寫在最後

由於項目中很少使用,所以這 API 給不了太多建議~~

此 API 的應用場景還是有的,可以想想下那些超大文件在線處理應用,比如 ZIP、PSD、PPT 之類的文件,可以將文件解析後存在 IndexedDB 中,在需要的時候查詢指定數據即可,這樣可以節約很多的解析時間。

只是需要注意,所有存在瀏覽器端的數據,用户清空緩存之後都將不復存在,所以在使用時需做好容錯處理~~

詳細文檔請參閲 MDN:https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

一個更加完善的項目:https://github.com/marco-c/eLibri

user avatar zaotalk Avatar freeman_tian Avatar aqiongbei Avatar chongdianqishi Avatar longlong688 Avatar anchen_5c17815319fb5 Avatar yuzhihui Avatar nqbefgvs Avatar libubai Avatar kongsq Avatar abc-x Avatar leoych Avatar
Favorites 61 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.