功能需求:
const DB_NAME = 'NotesApp'; const DB_VERSION = 1; function initDatabase() { return new Promise((resolve, reject) => { const request = indexedDB.open(DB_NAME, DB_VERSION); request.onupgradeneeded = (event) => { const db = event.target.result; // 笔记存储 const noteStore = db.createObjectStore('notes', { keyPath: 'id', autoIncrement: true }); noteStore.createIndex('updatedAtIndex', 'updatedAt', { unique: false }); noteStore.createIndex('tagIndex', 'tags', { multiEntry: true }); // 标签存储 const tagStore = db.createObjectStore('tags', { keyPath: 'name' }); // 同步队列 const syncStore = db.createObjectStore('syncQueue', { keyPath: 'id', autoIncrement: true }); syncStore.createIndex('statusIndex', 'status', { unique: false }); }; request.onsuccess = (event) => resolve(event.target.result); request.onerror = (event) => reject(event.target.error); }); }
class NotesApp { constructor(db) { this.db = db; } async createNote(title, content, tags = []) { const note = { title, content, tags, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), syncStatus: 'pending' }; const transaction = this.db.transaction(['notes', 'syncQueue'], 'readwrite'); const noteStore = transaction.objectStore('notes'); const syncStore = transaction.objectStore('syncQueue'); return new Promise((resolve, reject) => { const request = noteStore.add(note); request.onsuccess = () => { const noteId = request.result; // 添加到同步队列 syncStore.add({ action: 'create', storeName: 'notes', data: { ...note, id: noteId }, status: 'pending', createdAt: new Date().toISOString() }); resolve(noteId); }; request.onerror = () => reject(request.error); }); } async searchNotes(query) { const transaction = this.db.transaction(['notes'], 'readonly'); const store = transaction.objectStore('notes'); return new Promise((resolve, reject) => { const results = []; const request = store.openCursor(); request.onsuccess = (event) => { const cursor = event.target.result; if (cursor) { const note = cursor.value; // 简单全文搜索 if (note.title.includes(query) || note.content.includes(query)) { results.push(note); } cursor.continue(); } else { resolve(results); } }; request.onerror = () => reject(request.error); }); } async getNotesByTag(tag) { const transaction = this.db.transaction(['notes'], 'readonly'); const store = transaction.objectStore('notes'); const index = store.index('tagIndex'); return index.getAll(tag); } async getRecentNotes(limit = 10) { const transaction = this.db.transaction(['notes'], 'readonly'); const store = transaction.objectStore('notes'); const index = store.index('updatedAtIndex'); // 按更新时间倒序 return new Promise((resolve, reject) => { const results = []; const request = index.openCursor(null, 'prev'); request.onsuccess = (event) => { const cursor = event.target.result; if (cursor && results.length < limit) { results.push(cursor.value); cursor.continue(); } else { resolve(results); } }; request.onerror = () => reject(request.error); }); } }
function initTodoDB() { return new Promise((resolve, reject) => { const request = indexedDB.open('TodoApp', 1); request.onupgradeneeded = (event) => { const db = event.target.result; // 待办事项 const todoStore = db.createObjectStore('todos', { keyPath: 'id', autoIncrement: true }); todoStore.createIndex('statusIndex', 'status', { unique: false }); todoStore.createIndex('priorityIndex', 'priority', { unique: false }); todoStore.createIndex('dueDateIndex', 'dueDate', { unique: false }); todoStore.createIndex('projectIndex', 'projectId', { unique: false }); // 项目 const projectStore = db.createObjectStore('projects', { keyPath: 'id', autoIncrement: true }); // 活动日志 const logStore = db.createObjectStore('activityLogs', { keyPath: 'id', autoIncrement: true }); logStore.createIndex('todoIndex', 'todoId', { unique: false }); logStore.createIndex('timeIndex', 'timestamp', { unique: false }); }; request.onsuccess = (event) => resolve(event.target.result); request.onerror = (event) => reject(event.target.error); }); }
class TodoApp { constructor(db) { this.db = db; } async addTodo(todo) { const transaction = this.db.transaction(['todos', 'activityLogs'], 'readwrite'); const todoStore = transaction.objectStore('todos'); const logStore = transaction.objectStore('activityLogs'); const todoWithMeta = { ...todo, status: 'pending', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; return new Promise((resolve, reject) => { const request = todoStore.add(todoWithMeta); request.onsuccess = () => { const todoId = request.result; // 记录活动 logStore.add({ todoId, action: 'created', timestamp: new Date().toISOString(), details: { title: todo.title } }); resolve(todoId); }; request.onerror = () => reject(request.error); }); } async completeTodo(todoId) { const transaction = this.db.transaction(['todos', 'activityLogs'], 'readwrite'); const todoStore = transaction.objectStore('todos'); const logStore = transaction.objectStore('activityLogs'); const todo = await new Promise((resolve, reject) => { const request = todoStore.get(todoId); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); if (!todo) throw new Error('Todo not found'); todo.status = 'completed'; todo.completedAt = new Date().toISOString(); todo.updatedAt = new Date().toISOString(); return new Promise((resolve, reject) => { const request = todoStore.put(todo); request.onsuccess = () => { logStore.add({ todoId, action: 'completed', timestamp: new Date().toISOString() }); resolve(todo); }; request.onerror = () => reject(request.error); }); } async getTodosByStatus(status) { const transaction = this.db.transaction(['todos'], 'readonly'); const store = transaction.objectStore('todos'); const index = store.index('statusIndex'); return index.getAll(status); } async getOverdueTodos() { const transaction = this.db.transaction(['todos'], 'readonly'); const store = transaction.objectStore('todos'); const index = store.index('dueDateIndex'); const now = new Date().toISOString(); const range = IDBKeyRange.upperBound(now); const todos = await index.getAll(range); return todos.filter(todo => todo.status !== 'completed'); } }
class ImageGalleryDB { constructor(db) { this.db = db; } async storeImage(file, metadata = {}) { const arrayBuffer = await file.arrayBuffer(); const image = { name: file.name, type: file.type, size: file.size, data: arrayBuffer, thumbnail: await this.generateThumbnail(arrayBuffer), metadata: { ...metadata, uploadedAt: new Date().toISOString() } }; const transaction = this.db.transaction(['images'], 'readwrite'); const store = transaction.objectStore('images'); return new Promise((resolve, reject) => { const request = store.add(image); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } async generateThumbnail(arrayBuffer) { // 简化示例:实际应使用 Canvas 调整图片大小 return arrayBuffer.slice(0, 1024); // 占位符 } async getImage(id) { const transaction = this.db.transaction(['images'], 'readonly'); const store = transaction.objectStore('images'); return new Promise((resolve, reject) => { const request = store.get(id); request.onsuccess = () => { const record = request.result; if (record) { // 转为 Blob URL const blob = new Blob([record.data], { type: record.type }); record.url = URL.createObjectURL(blob); } resolve(record); }; request.onerror = () => reject(request.error); }); } }
本章通过三个实战案例展示了 IndexedDB 的应用:
继续阅读 第十三部分:存储技术对比。