前端 IndexDB 使用指南

目录

IndexedDB 一句话理解

📊 对比 localStorage

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

💡 使用示例

⚠️ 注意事项

IDB 完整使用指南

1. 安装与基础操作

安装

四个核心方法

2. 完整工具类封装

3. React 组件中使用

4. 关键概念说明

📌 必知要点

5. 官方资源

6. 故障排除


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。

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> </li> ))} </ul> {/* 统计信息 */} <div className="stats"> 总计: {tasks.length} 个任务 | 已完成: {tasks.filter(t => t.completed).length} | 未完成: {tasks.filter(t => !t.completed).length} </div> </div> ); } 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. 官方资源

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

Read more

工具篇-如何在Github Copilot中使用MCP服务?

工具篇-如何在Github Copilot中使用MCP服务?

Model Context Protocol (MCP) 是由 Anthropic 公司于 2024 年 11 月推出的一种开放协议标准,目的在于标准化 LLM 与外部数据源、工具及服务之间的交互方式。MCP 被广泛类比为“AI 领域的 USB-C 接口”。 一、vscode的安装 下载vscodeVisual Studio Code - Code Editing. Redefined安装完成打开 选择copilot,这个是AI助手,帮助你编程  然后注册登录,可以使用GitHub的账号登录,很多工具都可以通过GitHub帐号登录,所以注册一个GitHub帐号是很有必要的。 二、使用MCP 2.1 准备好MCP 先按这篇文章准备好高德地图的MCP:工具篇-Cherry Studio之MCP使用-ZEEKLOG博客 2.2 在Github Copilot中配置 MCP服务

VS Code+GitHub Copilot避坑指南:从安装配置到最佳实践的完整手册

VS Code + GitHub Copilot 深度驾驭手册:从避坑到精通的实战心法 如果你是一名 Visual Studio Code 的用户,并且对那个传说中能“读懂你心思”的 AI 编程伙伴 GitHub Copilot 感到好奇,甚至已经跃跃欲试,那么这篇文章就是为你准备的。我们不再重复那些泛泛而谈的“AI 将改变编程”的论调,而是直接切入核心:如何在你最熟悉的 VS Code 环境中,真正驯服 Copilot,让它从一个偶尔“胡言乱语”的助手,变成你编码流中如臂使指的高效组件。我们将聚焦于从安装配置的第一分钟开始,到融入你日常工作流的每一个细节,过程中你会遇到哪些真实的“坑”,以及如何优雅地跨过它们。这不是一篇简单的功能罗列,而是一份融合了配置技巧、心智模型和实战策略的深度指南。 1. 环境搭建与初始配置:奠定高效协作的基石 在兴奋地敲下第一行代码之前,一个稳固且经过优化的起点至关重要。许多初次使用者遇到的挫折,

GitHub Copilot 教程

文章来源:https://vscode.it-docs.cn/docs/copilot/overview.html GitHub Copilot 为 Visual Studio Code 增加了多代理开发功能。规划好你的方法,然后让AI代理在项目中实现并验证代码变更。并行运行多个代理会话:本地、后台或云端。从一个中心视角管理所有角色。内联建议、内联聊天和智能行为会帮助你完成整个编码流程。 代理与代理会话 代理端到端地处理完整的编码任务。给代理一个高级任务,它会将工作拆分成步骤,编辑文件,运行终端命令,调用工具,并在遇到错误或测试失败时自我纠正。每个任务都运行在一个代理会话中,这是一个持续存在的对话,你可以跟踪、暂停、继续或交接给另一个代理。 重要 你们组织可能在VS Code中禁用了代理。请联系你的管理员以启用此功能。 从中央视图管理会话 并行运行多个代理会话,每个会话专注于不同的任务。聊天面板中的会话视图为你提供了一个统一的地方来监控所有活跃会话,无论是本地运行、后台还是云端运行。查看每次会话的状态,切换,查看文件变更,

Flutter for OpenHarmony 实战:疯狂头像 App(四)— 通义万相 AIGC 联调与相册持久化实战

Flutter for OpenHarmony 实战:疯狂头像 App(四)— 通义万相 AIGC 联调与相册持久化实战

Jan-31-2026 23-32-23 Flutter for OpenHarmony 实战:疯狂头像 App(四)— 通义万相 AIGC 联调与相册持久化实战 摘要:行百里者半九十。本文作为“疯狂头像”(Crazy Avatar)实战系列的终章,我们将完成从 AI 异步生成到图片系统级保存的全链路闭环。本文将重点攻克鸿蒙(HarmonyOS)侧的 module.json5 权限合规、媒体库写入逻辑及网络请求健壮性处理,助你打造商业级 AIGC 应用。 前言 在之前的《动效篇》中,我们为应用注入了生动的灵魂。但一个真正的 AI 工具,如果不能产生“作品”并持久化到物理存储,它就只是一个精致的“空中楼阁”。 在鸿蒙(HarmonyOS Next)生态中,文件的存储安全与权限管理有着极其严格的标准。