看新闻不看热闹 發表於 2025-8-28 10:27:00

Web前端入门第 85 问:JavaScript 一个简单的 IndexedDB 数据库入门示例

<p>在前端风风雨雨的混了多年,从没在项目中实际使用过 <code>IndexedDB</code> 这个浏览器端的数据库,所以今天就摸了下 MDN 的后门,写一个简单的入门示例。</p>
<p>页面大概长这样:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202508/596097-20250828102714055-2089694258.png"></p>
<p><strong>源码:</strong></p>
<p>以下代码包含了一个数据库所有的 <code>CRUD</code> (增删改查)操作。</p>
<pre><code class="language-html">&lt;div&gt;
&lt;button id="js_add_btn"&gt;添加书籍&lt;/button&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;input type="text" name="" id="js_book_id" placeholder="输入书籍ID"/&gt;
&lt;button id="js_get_by_id_btn"&gt;查询书籍&lt;/button&gt;
&lt;button id="js_update_by_id_btn"&gt;更新书籍&lt;/button&gt;
&lt;button id="js_delete_by_id_btn"&gt;删除书籍&lt;/button&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;input type="text" name="" id="js_book_author" placeholder="输入书籍作者查询"/&gt;&lt;button id="js_get_by_author_btn"&gt;查询书籍&lt;/button&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;button id="js_get_all_btn"&gt;查询所有书籍&lt;/button&gt;
&lt;/div&gt;
&lt;div id="output"&gt;&lt;/div&gt;

&lt;script&gt;
(() =&gt; {
    // 数据库配置
    const dbName = 'MyDB';
    const storeName = 'books';
    const output = document.getElementById('output')
    let db = null;

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

    // 初始化数据库
    const initDB = () =&gt; {
      const request = indexedDB.open(dbName);

      // 数据库升级/创建时触发
      request.onupgradeneeded = (event) =&gt; {
      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) =&gt; {
      db = event.target.result;
      console.log('数据库已打开');
      };

      // 数据库打开失败
      request.onerror = (event) =&gt; {
      console.error('数据库错误:', event.target.error);
      setOutputContent('数据库错误');
      };
    };

    // 封装包装函数,用于执行数据库相关方法
    function wrapper(func) {
      return new Promise((resolve, reject) =&gt; {
      const transaction = db.transaction(, 'readwrite');
      const store = transaction.objectStore(storeName);
      const res = func(store)
      res.onsuccess = () =&gt; {
          resolve(res.result)
      };

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

    // 添加数据
    const addBook = async (book) =&gt; {
      try {
      const result = await wrapper((store) =&gt; store.add(book))
      console.log(result);
      setOutputContent(`添加成功!书籍ID: ${result}`);
      } catch (error) {
      console.error(error);
      setOutputContent('添加失败');
      }
    };

    // 通过ID查询数据
    const getBook = async (id) =&gt; {
      try {
      const book = await wrapper((store) =&gt; 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 () =&gt; {
      try {
      const book = await wrapper((store) =&gt; store.getAll())
      if (book) {
          console.log('查询结果:', book);
          setOutputContent(`总数:${book.length}`);
      } else {
          console.log('未找到书籍');
          setOutputContent('未找到该书籍');
      }
      } catch (error) {
      console.error(error);
      setOutputContent('查询失败');
      }
    };

    // 更新数据--数据不存在时会添加数据
    const updateBook = async (book) =&gt; {
      try {
      const result = await wrapper((store) =&gt; store.put(book))
      console.log(result);
      setOutputContent(`更新成功!结果: ${result}`);
      } catch (error) {
      console.error(error);
      setOutputContent('更新失败');
      }
    };

    // 删除数据
    const deleteBook = async (id) =&gt; {
      try {
      const result = await wrapper((store) =&gt; store.delete(id))
      console.log(result);
      setOutputContent(`删除成功!结果: ${result}`);
      } catch (error) {
      console.error(error);
      setOutputContent('删除失败');
      }
    };
    // 根据作者查询
    const getByAuthor = async (author) =&gt; {
      try {
      const result = await wrapper((store) =&gt; {
          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 = () =&gt; {
      addBook({
      title: 'Web前端入门',
      author: '前端路引',
      price: (0.99 * Math.random() + 10) .toFixed(2),
      });
    };

    // 根据ID查询
    document.getElementById('js_get_by_id_btn').onclick = () =&gt; {
      const bookId = document.getElementById('js_book_id').value;
      getBook(Number(bookId));
    };

    // 根据ID删除
    document.getElementById('js_delete_by_id_btn').onclick = () =&gt; {
      const bookId = document.getElementById('js_book_id').value;
      deleteBook(Number(bookId));
    };

    // 根据ID更新
    document.getElementById('js_update_by_id_btn').onclick = () =&gt; {
      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 = () =&gt; {
      const author = document.getElementById('js_book_author').value
      getByAuthor(author);
    };

    // 查询全部
    document.getElementById('js_get_all_btn').onclick = () =&gt; {
      getAllBook();
    };

    // 页面加载时初始化数据库
    initDB();
})();
&lt;/script&gt;
</code></pre>
<h2 id="indexeddb-大小限制">IndexedDB 大小限制</h2>
<p>以下内容为 AI 回答:</p>
<p><img src="https://img2024.cnblogs.com/blog/596097/202508/596097-20250828102723413-214796515.png"></p>
<h2 id="获取可用的存储空间大小">获取可用的存储空间大小</h2>
<pre><code class="language-js">navigator.storage.estimate().then((estimate) =&gt; {
console.log(
    `已使用:`,
    (
      (estimate.usage / estimate.quota) * 100
    ).toFixed(2)
);
console.log(`可使用:`, (estimate.quota / 1024 / 1024).toFixed(2) + "MB");
});
</code></pre>
<p>相关文档:https://developer.mozilla.org/en-US/docs/Web/API/Storage_API</p>
<h2 id="写在最后">写在最后</h2>
<p>由于项目中很少使用,所以这 API 给不了太多建议~~</p>
<p>此 API 的应用场景还是有的,可以想想下那些超大文件<strong>在线处理</strong>应用,比如 ZIP、PSD、PPT 之类的文件,可以将文件解析后存在 IndexedDB 中,在需要的时候查询指定数据即可,这样可以节约很多的解析时间。</p>
<p>只是需要注意,所有存在浏览器端的数据,用户清空缓存之后都将不复存在,所以在使用时需做好容错处理~~</p>
<p>详细文档请参阅 MDN:https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API</p>
<p>一个更加完善的项目:https://github.com/marco-c/eLibri</p>


</div>
<div id="MySignature" role="contentinfo">
    <p>&nbsp;</p>
<p style="font-size: 18px;font-weight: bold;">文章首发于微信公众号【<span style="color:rgb(255, 71, 87)">前端路引</span>】,欢迎 <span style="color:#4ec259">微信扫一扫</span> 查看更多文章。</p>
<p>
<img style="max-width: 320px;" src="https://images.cnblogs.com/cnblogs_com/linx/2447020/o_250228035031_%E5%85%AC%E4%BC%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png"/>
</p>
<p>本文来自博客园,作者:前端路引,转载请注明原文链接:https://www.cnblogs.com/linx/p/19062137</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/linx/p/19062137
頁: [1]
查看完整版本: Web前端入门第 85 问:JavaScript 一个简单的 IndexedDB 数据库入门示例