angular使用IndexedDb实现增删改查sql

server/2025/2/28 1:08:46/

说明:我听说前端有一款数据库,叫IndexedDb数据库,可以存储超大的文件和数据,大约有250M,有了这个,就可以在浏览器里面,存储超大的数据,
事实上IndexedDb存储的数据,存在浏览器文件夹的c盘,缓存浏览器的文件夹里面,只要你存了数据,用户关闭浏览器,再次打开,数据依然还在,可以加载,用来做缓存,非常方便
因此,我就计划用angular框架,使用indexdb技术,先写一个简单的增删改查的小demo,用来存储用户信息,弄了一上午,总算可以用了,下面是详细步骤和效果图

效果图:
在这里插入图片描述

step0:用npm安装IndexedDb

npm install ngx-indexed-db 

step1:IndexedDb安装成功后,在 package.json可以查看安装的IndexedDb版本19.3.3

 "@angular/animations": "^19.1.0","@angular/cdk": "^19.1.5","@angular/common": "^19.1.0","@angular/compiler": "^19.1.0","@angular/core": "^19.1.0","@angular/forms": "^19.1.0","@angular/material": "^19.1.5","@angular/platform-browser": "^19.1.0","@angular/platform-browser-dynamic": "^19.1.0","@angular/router": "^19.1.0","ngx-indexed-db": "^19.3.3","rxjs": "~7.8.0","tslib": "^2.3.0","zone.js": "~0.15.0"

step2:接下来需要在angular项目中,导入IndexedDb
新建一个文件,文件名和具体路径是:C:\Users\Administrator\WebstormProjects\untitled4\src\app\db.config.ts

import { DBConfig } from 'ngx-indexed-db';export const DB_CONFIG: DBConfig = {name: 'Angular19DB',version: 2,objectStoresMeta: [{store: 'tasks',storeConfig: {keyPath: 'id',autoIncrement: true},storeSchema: [{ name: 'title', keypath: 'title', options: { unique: false } },{ name: 'status', keypath: 'status', options: { unique: false } }]}]
};

step3:然后就是注册,
文件名和具体路径是:C:\Users\Administrator\WebstormProjects\untitled4\src\app\app.config.ts

import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';import { routes } from './app.routes';
import { provideIndexedDb } from 'ngx-indexed-db';
import { DB_CONFIG } from './db.config';import { provideAnimations } from '@angular/platform-browser/animations';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';export const appConfig: ApplicationConfig = {providers: [provideIndexedDb(DB_CONFIG),provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes),provideAnimations(), provideAnimationsAsync()]
};

step4:路由这些,不用我多说了吧,新建一个模块,添加到路由里面,然后就直接开整,

 ng generate component student

step5:C:\Users\Administrator\WebstormProjects\untitled4\src\app\student\student.component.ts

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { DatabaseService } from './data.service';
import { FormsModule } from '@angular/forms';
import { NgForOf } from '@angular/common';
import { Task } from './task.model';// 从统一定义文件导入@Component({selector: 'app-task',imports: [FormsModule, NgForOf],templateUrl: './student.component.html',styleUrl: './student.component.css'
})export class StudentComponent  implements OnInit {tasks: Task[] = [];newTask: Omit<Task, 'id'> = {title: '',status: 'pending'};constructor(private db: DatabaseService,private cdr: ChangeDetectorRef) {}async ngOnInit() {await this.loadTasks();}async loadTasks() {// 添加类型断言确保数据一致性this.tasks = await this.db.getAllTasks() as Task[];this.cdr.detectChanges();}async addTask() {if (this.newTask.title.trim()) {// 类型安全传递await this.db.addTask(this.newTask);this.newTask = { title: '', status: 'pending' };await this.loadTasks();}}async updateTask(task: Task) {// 添加空值检查if (task.id === undefined) return;await this.db.updateTask(task);await this.loadTasks();}async deleteTask(id: number) {await this.db.deleteTask(id);await this.loadTasks();}
}

step6:C:\Users\Administrator\WebstormProjects\untitled4\src\app\student\task.model.ts

// src/app/models/task.model.ts
export interface Task {id?: number;  // 将id改为可选属性title: string;status: 'pending' | 'completed';
}

step7:C:\Users\Administrator\WebstormProjects\untitled4\src\app\student\data.service.ts

import { Injectable } from '@angular/core';
import { Task } from './task.model';@Injectable({ providedIn: 'root' })
export class DatabaseService {private db!: IDBDatabase;private readonly dbName = 'AngularDB';private readonly storeName = 'tasks';// 添加数据库准备状态追踪private dbReady: Promise<void>;constructor() {this.dbReady = this.initializeDB();}private async initializeDB(): Promise<void> {return new Promise((resolve, reject) => {const request = indexedDB.open(this.dbName, 1);request.onupgradeneeded = (event) => {this.db = (event.target as IDBOpenDBRequest).result;if (!this.db.objectStoreNames.contains(this.storeName)) {const store = this.db.createObjectStore(this.storeName, {keyPath: 'id',autoIncrement: true});store.createIndex('title', 'title', { unique: false });}};request.onsuccess = (event) => {this.db = (event.target as IDBOpenDBRequest).result;resolve();};request.onerror = (event) => {reject((event.target as IDBRequest).error);};});}// 所有方法添加等待初始化async getAllTasks(): Promise<Task[]> {await this.dbReady;return new Promise((resolve, reject) => {const transaction = this.db.transaction(this.storeName, 'readonly');const store = transaction.objectStore(this.storeName);const request = store.getAll();request.onsuccess = () => resolve(request.result);request.onerror = () => reject(request.error);});}async addTask(task: Omit<Task, 'id'>): Promise<number> {await this.dbReady;return new Promise((resolve, reject) => {const transaction = this.db.transaction(this.storeName, 'readwrite');const store = transaction.objectStore(this.storeName);const request = store.add(task);request.onsuccess = () => resolve(request.result as number);request.onerror = () => reject(request.error);});}async updateTask(task: Task): Promise<void> {await this.dbReady;if (task.id === undefined) {throw new Error('Cannot update task without ID');}return new Promise((resolve, reject) => {const transaction = this.db.transaction(this.storeName, 'readwrite');const store = transaction.objectStore(this.storeName);const request = store.put(task);request.onsuccess = () => resolve();request.onerror = () => reject(request.error);});}async deleteTask(id: number): Promise<void> {await this.dbReady;return new Promise((resolve, reject) => {const transaction = this.db.transaction(this.storeName, 'readwrite');const store = transaction.objectStore(this.storeName);const request = store.delete(id);request.onsuccess = () => resolve();request.onerror = () => reject(request.error);});}
}

step8:C:\Users\Administrator\WebstormProjects\untitled4\src\app\student\student.component.html

<div class="task-manager"><div class="task-header"><input[(ngModel)]="newTask.title"placeholder="Enter task title"class="task-input"(keyup.enter)="addTask()"><buttonclass="primary-btn"(click)="addTask()">+ Add Task</button></div><div class="task-list"><div *ngFor="let task of tasks" class="task-item"><input[(ngModel)]="task.title"class="task-input"><select[(ngModel)]="task.status"(change)="updateTask(task)"class="status-select"><option value="pending">⏳ Pending</option><option value="completed">✅ Completed</option></select><buttonclass="danger-btn"(click)="deleteTask(task.id!)">🗑 Delete</button></div></div>
</div>

step9:C:\Users\Administrator\WebstormProjects\untitled4\src\app\student\student.component.css

/* 现代配色方案 */
.task-manager {max-width: 800px;margin: 2rem auto;padding: 2rem;background: white;border-radius: 12px;box-shadow: 0 8px 24px rgba(0, 0, 0, 0.05);
}.task-header {display: flex;gap: 1rem;margin-bottom: 2rem;
}.task-input {flex: 1;padding: 12px;border: 2px solid #e9ecef;border-radius: 8px;font-size: 16px;transition: border-color 0.3s ease;
}
.task-input:focus {outline: none;border-color: #4a90e2;box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}.primary-btn {padding: 10px 20px;border: none;border-radius: 8px;cursor: pointer;font-weight: 500;transition: all 0.3s ease;display: inline-flex;align-items: center;gap: 8px;background: linear-gradient(135deg, #4a90e2 0%, #2d7ff9 100%);color: white;
}
.primary-btn:hover {transform: translateY(-1px);box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);background: linear-gradient(135deg, #3d85d6 0%, #2770e0 100%);
}
.primary-btn:active {transform: translateY(0);
}.danger-btn {padding: 10px 20px;border: none;border-radius: 8px;cursor: pointer;font-weight: 500;transition: all 0.3s ease;display: inline-flex;align-items: center;gap: 8px;background: linear-gradient(135deg, #ff4757 0%, #ff6b81 100%);color: white;
}
.danger-btn:hover {transform: translateY(-1px);box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.danger-btn:active {transform: translateY(0);
}.task-list {display: flex;flex-direction: column;gap: 1rem;
}.task-item {display: flex;gap: 1rem;align-items: center;padding: 1.5rem;background: #f8f9fa;border-radius: 8px;transition: transform 0.3s ease;
}
.task-item:hover {transform: translateX(5px);
}.status-select {padding: 8px 12px;border: 2px solid #e9ecef;border-radius: 6px;background: white;cursor: pointer;transition: all 0.3s ease;
}
.status-select:focus {outline: none;border-color: #4a90e2;
}

直接点击运行,然后success

end


http://www.ppmy.cn/server/171174.html

相关文章

【Redis 原理】通信协议 内存回收

文章目录 通信协议--RESP内存回收内存过期策略惰性删除周期删除 内存淘汰策略 通信协议–RESP Redis是一个CS架构的软件&#xff0c;通信一般分两步&#xff08;不包括pipeline和PubSub&#xff09;&#xff1a; 客户端&#xff08;client&#xff09;向服务端&#xff08;se…

计算机主板南桥与北桥核心架构概论

在计算机主板的设计中&#xff0c;“南北桥”架构曾是非常重要的组成部分&#xff0c;它负责管理和协调各类硬件设备之间的通信与协作。随着技术的进步&#xff0c;南北桥架构逐渐被更先进的集成方案所取代&#xff0c;但了解其工作原理对于理解计算机硬件发展历史仍然非常有意…

基于Springboot的小说网站【附源码】

基于Springboot的小说网站 效果如下&#xff1a; 系统主页面 书库信息页面 书籍详情页面 推荐信息页面 小说推荐页面 书库信息页面 小说排行榜页面 系统管理页面 研究背景 随着互联网技术的快速发展&#xff0c;网络文学逐渐成为一种新兴的文学形式&#xff0c;吸引了大量读…

【无标题】docker-compose ps 和dokcer ps的区别

docker-compose ps 和 docker ps 是两个用于查看 Docker 容器状态的命令&#xff0c;但它们在功能和显示的信息上有所区别&#xff1a; docker ps 基本功能&#xff1a; Docker ps 是 Docker 的原生命令&#xff0c;用于列出当前主机上运行的所有 Docker 容器。 显示信息&…

【多模态大模型学习】位置编码的学习记录

【多模态大模型学习】位置编码的学习记录 0.前言1. sinusoidal编码1.0 数学知识——复数1.0.1 复数乘法、共轭复数1.0.2 复数的指数表示 1.1 sinusoidal编码来历1.2 代码实现 2. Rotary Positional Embedding (RoPE) ——旋转位置编码2.1 RoPE来历2.2 代码实现2.2.1 GPT-J风格的…

改进A*算法并用于城市无人机路径规划

独家原创&#xff01;改进A*算法进行城市无人机路径规划&#xff0c;考虑碰撞&#xff0c;飞行高度等优化启发式搜索。所有指标超过A*和A算法&#xff01;附有完整的文档说明 算法设计、毕业设计、期刊专利&#xff01;感兴趣可以联系我。 &#x1f3c6;代码获取方式1&#xff…

电子电气架构 --- 主机厂电子电气架构演进

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

python如何去除列表末尾的None

在 Python 中&#xff0c;你可以使用列表切片或者列表推导式等方法来去除列表末尾的 None 值。这里有几个方法可以实现这个目的&#xff1a; 方法一&#xff1a;使用列表切片和 rstrip 方法&#xff08;针对字符串列表的模拟&#xff0c;但需要先转换&#xff09; 虽然 rstri…