跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

前端 IndexedDB 本地数据库使用指南

介绍浏览器端 IndexedDB 本地数据库的使用。对比了其与 localStorage 在容量、数据类型及查询方式上的差异,明确了离线应用、大量数据缓存等适用场景。提供了基于 idb 库的基础操作、工具类封装及 React 组件集成示例,涵盖增删改查、版本升级及索引创建等关键概念,并包含官方资源与故障排除指南。

黑客发布于 2026/4/6更新于 2026/10/19101 浏览

IndexedDB 一句话理解

浏览器里的大容量本地数据库,比 localStorage 能存更多、更复杂的数据。

📊 对比 localStorage

特性localStorageIndexedDB
容量5MB至少 250MB,甚至 GB 级
数据类型字符串任何 JS 对象、文件、二进制
查询方式键值对键值、索引、范围查询
速度同步(阻塞)异步(不阻塞页面)

🎯 使用场景(什么时候用?)

用 localStorage:

  • 存 token、用户设置等小数据
  • 简单键值对,数据量 < 5MB

用 IndexedDB:

  • 离线应用的全部数据
  • 用户生成的内容(图片、笔记)
  • 应用缓存(大量 API 数据)
  • 编辑器草稿自动保存

💡 使用示例

// 存文件/图片
await db.put('files', { id: 'photo1', name: '头像.jpg', data: fileBlob, // 二进制文件 size: '2MB' });
// 复杂查询(localStorage 做不到)
const expensiveProducts = await db
  .getAllFromIndex('products', 'price', IDBKeyRange.lowerBound(1000));

⚠️ 注意事项

不要用 IndexedDB 存:

  • 密码等敏感信息(不安全)
  • 实时同步数据(用 WebSocket)
  • 服务器端数据(用 API)

应该用 IndexedDB 存:

  • 离线可用的用户数据
  • 大型应用的本地缓存
  • 用户上传的文件本地副本

一句话总结:需要存大量复杂数据且支持离线访问时,用 IndexedDB。

目录

  1. IndexedDB 一句话理解
  2. 📊 对比 localStorage
  3. 🎯 使用场景(什么时候用?)
  4. 💡 使用示例
  5. ⚠️ 注意事项
  6. IDB 完整使用指南
  7. 1. 安装与基础操作
  8. 安装
  9. 四个核心方法
  10. 2. 完整工具类封装
  11. 3. React 组件中使用
  12. 4. 关键概念说明
  13. 📌 必知要点
  14. 5. 官方资源
  15. 6. 故障排除

IDB 完整使用指南

1. 安装与基础操作

安装
yarn add idb
四个核心方法
import { openDB } from 'idb';
// 1. 打开/创建数据库(首次运行时会自动创建)
const db = await openDB('MyAppDB', 1, {
  // 参数:数据库名,版本号
  upgrade(db) {
    // 只在版本更新或初次创建时执行
    // 创建对象仓库(相当于数据库表)
    db.createObjectStore('tasks', { keyPath: 'id' // 指定主键为 id 字段 });
  }
});
// 2. 添加或更新数据
await db.put('tasks', { id: 1, // 必须有 id 字段,作为主键 title: '学习 IDB', completed: false });
// 3. 查询所有数据
const allTasks = await db.getAll('tasks');
// 4. 根据 id 查询单条
const task = await db.get('tasks', 1);
// 5. 根据 id 删除
await db.delete('tasks', 1);

2. 完整工具类封装

import { openDB } from 'idb';
class TaskDB {
  constructor() {
    this.dbName = 'TaskDatabase';
    this.storeName = 'tasks';
    this.version = 1;
  }
  // 初始化数据库连接
  async connect() {
    return openDB(this.dbName, this.version, {
      upgrade(db) {
        // 如果 tasks 表不存在就创建
        if (!db.objectStoreNames.contains('tasks')) {
          db.createObjectStore('tasks', { keyPath: 'id' // 主键字段 });
        }
      }
    });
  }
  // 增/改:保存任务
  async saveTask(task) {
    const db = await this.connect();
    // put 方法:id 存在则更新,不存在则新增
    return db.put(this.storeName, task);
  }
  // 删:删除任务
  async deleteTask(id) {
    const db = await this.connect();
    return db.delete(this.storeName, id);
  }
  // 查:获取所有任务
  async getAllTasks() {
    const db = await this.connect();
    return db.getAll(this.storeName);
  }
  // 查:根据 id 获取单个任务
  async getTask(id) {
    const db = await this.connect();
    return db.get(this.storeName, id);
  }
}
export default new TaskDB(); // 导出单例实例

3. React 组件中使用

import React, { useState, useEffect } from 'react';
import taskDB from './taskDB'; // 导入上面封装的数据库工具

function TaskManager() {
  const [tasks, setTasks] = useState([]);
  const [newTaskTitle, setNewTaskTitle] = useState('');

  // 组件加载时从数据库读取所有任务
  useEffect(() => {
    loadTasks();
  }, []);

  // 从数据库加载任务
  const loadTasks = async () => {
    const savedTasks = await taskDB.getAllTasks();
    setTasks(savedTasks || []); // 处理空数据情况
  };

  // 添加新任务
  const handleAddTask = async () => {
    if (!newTaskTitle.trim()) return;
    const newTask = {
      id: Date.now(), // 使用时间戳作为唯一 ID
      title: newTaskTitle,
      completed: false,
      createdAt: new Date().toISOString()
    };
    // 1. 保存到数据库
    await taskDB.saveTask(newTask);
    // 2. 更新界面状态
    setTasks([...tasks, newTask]);
    setNewTaskTitle('');
  };

  // 切换任务完成状态
  const handleToggleTask = async (task) => {
    const updatedTask = { ...task, completed: !task.completed };
    // 1. 更新数据库
    await taskDB.saveTask(updatedTask);
    // 2. 更新界面状态
    setTasks(tasks.map(t => t.id === task.id ? updatedTask : t));
  };

  // 删除任务
  const handleDeleteTask = async (taskId) => {
    // 1. 从数据库删除
    await taskDB.deleteTask(taskId);
    // 2. 从界面状态删除
    setTasks(tasks.filter(task => task.id !== taskId));
  };

  return (
    <div className="task-manager">
      <h1>任务管理器</h1>
      {/* 添加任务表单 */}
      <div className="add-task">
        <input type="text" value={newTaskTitle} onChange={(e) => setNewTaskTitle(e.target.value)} placeholder="输入新任务..." />
        <button onClick={handleAddTask}>添加</button>
      </div>
      {/* 任务列表 */}
      <ul className="task-list">
        {tasks.map(task => (
          <li key={task.id} className={task.completed ? 'completed' : ''}>
            <input type="checkbox" checked={task.completed} onChange={() => handleToggleTask(task)} />
            <span>{task.title}</span>
            <button onClick={() => handleDeleteTask(task.id)} className="delete-btn">删除</button>
          
        ))}
      
      {/* 统计信息 */}
      总计:{tasks.length} 个任务 | 已完成:{tasks.filter(t => t.completed).length} | 未完成:{tasks.filter(t => !t.completed).length}
    
  );
}
export default TaskManager;

4. 关键概念说明

📌 必知要点
  1. keyPath: 'id':指定数据的主键字段,每条数据必须有唯一的 id
  2. put() vs add():
    • put():id 存在则更新,不存在则新增
    • add():只能新增,id 重复会报错
  3. 版本控制:修改数据库结构时需增加版本号
// 版本升级示例
openDB('MyDB', 2, { // 版本从 1 升到 2
  upgrade(db, oldVersion) {
    if (oldVersion < 1) {
      // 初始创建
      db.createObjectStore('tasks', { keyPath: 'id' });
    }
    if (oldVersion < 2) {
      // 新增索引(可按标题搜索)
      const store = db.transaction.objectStore('tasks');
      store.createIndex('title', 'title');
    }
  }
});

5. 官方资源

  • GitHub 仓库:jakearchibald/idb
  • 完整 API 文档:仓库中的 README 文件
  • 在线体验:IDB 示例

6. 故障排除

// 1. 确保所有操作都是异步的
try {
  const db = await openDB(...);
  await db.put(...);
} catch (error) {
  console.error('数据库错误:', error);
}
// 2. 检查浏览器兼容性
if (!window.indexedDB) {
  alert('您的浏览器不支持 IndexedDB');
}
// 3. 清除缓存(开发时有用)
indexedDB.deleteDatabase('MyAppDB');

💡 一句话总结:openDB 打开数据库,put 保存数据,get 查询数据,delete 删除数据,所有操作都要加 await.

</li>
</ul>
<div className="stats">
</div>
</div>

更多推荐文章

查看全部
  • Google AI Studio 全指南:从入门到精通 Gemini 开发
  • OpenCode Superpowers 插件安装及实战使用指南
  • 网络安全行业人才缺口与薪资水平深度解析
  • Redis Hash 类型详解与常用命令实战
  • 豆包 Seedream 4.0 多图融合与主体一致性技术评测
  • Windows 11 安装 Git 完整指南
  • Rust 重构 Android 蓝牙协议栈:C++ 迁移的安全与效率实践
  • OpenClaw 多飞书机器人与多 Agent 团队实战复盘
  • Windows 11 Docker Desktop 安装与配置指南
  • WebSocket 与 WebRTC:Web 实时通信与音视频通信实战
  • 基于 Java + SpringBoot + UniApp 的待办事项提醒小程序设计与实现
  • 使用昇腾 Atlas 300I Duo 推理卡部署 32B 大语言模型 (MindIE+WebUI)
  • C++ 继承与多态机制详解
  • Megick Studio 桌面客户端下载 2026
  • 分治算法详解:快速排序、归并排序与快速选择
  • AMD显卡AI绘画终极指南:解锁ComfyUI-Zluda隐藏性能
  • 文心一言 4.5 开源模型 ERNIE-4.5-0.3B 轻量化部署与优化
  • 英文论文 AI 率检测:IThenticate 与 Turnitin 系统对比
  • Windows 本地部署 OpenClaw 接入飞书机器人
  • 耳机阻抗与前端适配:32Ω至 300Ω耳机的推力需求解析

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online