IndexedDB是浏览器提供的NoSQL数据库,用于在客户端存储大量结构化数据。与Web存储相比,IndexedDB支持更大的存储空间、索引查询和事务处理,适合离线应用和需要存储大量数据的Web应用。
东巴文(db-w.cn) 认为:IndexedDB是浏览器中的数据库引擎,为Web应用提供了强大的本地数据存储能力。
| 特点 | 说明 |
|---|---|
| 大容量 | 存储空间可达数百MB甚至更多 |
| 结构化存储 | 支持对象存储,可存储复杂对象 |
| 索引查询 | 支持创建索引,快速查询数据 |
| 事务支持 | 支持事务操作,保证数据一致性 |
| 异步API | 不阻塞主线程,性能更好 |
| 同源策略 | 遵循同源策略,数据安全 |
| 特性 | IndexedDB | localStorage | Cookie |
|---|---|---|---|
| 存储大小 | 大(数百MB+) | 小(5MB) | 很小(4KB) |
| 数据类型 | 对象、数组、Blob等 | 字符串 | 字符串 |
| 查询能力 | 支持索引查询 | 无 | 无 |
| 事务支持 | 支持 | 不支持 | 不支持 |
| API类型 | 异步 | 同步 | 同步 |
| 性能 | 高 | 中 | 低 |
东巴文点评:IndexedDB适合存储大量结构化数据,如离线应用数据、用户数据缓存等。
数据库是IndexedDB的最顶层容器,每个域名可以创建多个数据库。
对象存储类似于关系数据库中的表,用于存储JavaScript对象。
索引用于快速查询数据,可以在对象存储的属性上创建索引。
事务用于保证数据操作的原子性、一致性和隔离性。
每个存储的对象必须有一个键,可以是自动生成的,也可以是对象属性。
// 打开或创建数据库
const request = indexedDB.open('myDatabase', 1);
// 成功回调
request.onsuccess = function(event) {
const db = event.target.result;
console.log('数据库打开成功');
};
// 错误回调
request.onerror = function(event) {
console.error('数据库打开失败:', event.target.error);
};
// 升级回调(创建或升级数据库时触发)
request.onupgradeneeded = function(event) {
const db = event.target.result;
console.log('数据库升级');
// 创建对象存储
if (!db.objectStoreNames.contains('users')) {
const objectStore = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true });
console.log('对象存储创建成功');
}
};
东巴文点评:onupgradeneeded事件在数据库首次创建或版本号升级时触发,是创建对象存储和索引的最佳时机。
// 打开版本2的数据库
const request = indexedDB.open('myDatabase', 2);
request.onupgradeneeded = function(event) {
const db = event.target.result;
// 版本1到版本2的升级
if (event.oldVersion < 1) {
// 创建users对象存储
const userStore = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true });
userStore.createIndex('email', 'email', { unique: true });
}
if (event.oldVersion < 2) {
// 创建products对象存储
const productStore = db.createObjectStore('products', { keyPath: 'id', autoIncrement: true });
productStore.createIndex('name', 'name', { unique: false });
productStore.createIndex('price', 'price', { unique: false });
}
};
request.onupgradeneeded = function(event) {
const db = event.target.result;
// 创建对象存储,使用id作为键,自动递增
const userStore = db.createObjectStore('users', {
keyPath: 'id',
autoIncrement: true
});
// 创建对象存储,使用email作为键
const emailStore = db.createObjectStore('usersByEmail', {
keyPath: 'email'
});
// 创建对象存储,使用自动生成的键
const autoStore = db.createObjectStore('autoId', {
autoIncrement: true
});
};
request.onupgradeneeded = function(event) {
const db = event.target.result;
const userStore = db.createObjectStore('users', {
keyPath: 'id',
autoIncrement: true
});
// 创建唯一索引
userStore.createIndex('email', 'email', { unique: true });
// 创建非唯一索引
userStore.createIndex('name', 'name', { unique: false });
// 创建复合索引
userStore.createIndex('nameAge', ['name', 'age'], { unique: false });
};
| 选项 | 说明 |
|---|---|
unique |
是否唯一(true/false) |
multiEntry |
是否为数组的每个元素创建索引(true/false) |
function addData(db) {
// 创建事务
const transaction = db.transaction(['users'], 'readwrite');
// 获取对象存储
const objectStore = transaction.objectStore('users');
// 添加数据
const request = objectStore.add({
name: '张三',
email: 'zhangsan@example.com',
age: 25
});
request.onsuccess = function(event) {
console.log('数据添加成功,ID:', event.target.result);
};
request.onerror = function(event) {
console.error('数据添加失败:', event.target.error);
};
}
function putData(db) {
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
// put方法:如果键存在则更新,不存在则添加
const request = objectStore.put({
id: 1,
name: '李四',
email: 'lisi@example.com',
age: 30
});
request.onsuccess = function(event) {
console.log('数据添加或更新成功');
};
}
东巴文点评:add方法只能添加新数据,如果键已存在会报错;put方法既可以添加也可以更新。
function getDataByKey(db, id) {
const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const request = objectStore.get(id);
request.onsuccess = function(event) {
const user = event.target.result;
if (user) {
console.log('用户信息:', user);
} else {
console.log('未找到用户');
}
};
request.onerror = function(event) {
console.error('读取失败:', event.target.error);
};
}
function getDataByIndex(db, email) {
const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
// 获取索引
const index = objectStore.index('email');
// 根据索引查询
const request = index.get(email);
request.onsuccess = function(event) {
const user = event.target.result;
if (user) {
console.log('用户信息:', user);
} else {
console.log('未找到用户');
}
};
}
function getAllData(db) {
const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const request = objectStore.getAll();
request.onsuccess = function(event) {
const users = event.target.result;
console.log('所有用户:', users);
};
}
function cursorData(db) {
const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const request = objectStore.openCursor();
request.onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
console.log('用户:', cursor.value);
cursor.continue(); // 继续下一个
} else {
console.log('遍历完成');
}
};
}
function updateData(db, id) {
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
// 先读取数据
const getRequest = objectStore.get(id);
getRequest.onsuccess = function(event) {
const user = event.target.result;
if (user) {
// 修改数据
user.name = '王五';
user.age = 28;
// 更新数据
const putRequest = objectStore.put(user);
putRequest.onsuccess = function(event) {
console.log('数据更新成功');
};
} else {
console.log('未找到用户');
}
};
}
function updateByCursor(db) {
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
const request = objectStore.openCursor();
request.onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
const user = cursor.value;
// 修改数据
user.age += 1;
// 更新当前游标位置的数据
cursor.update(user);
cursor.continue();
} else {
console.log('更新完成');
}
};
}
function deleteData(db, id) {
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
const request = objectStore.delete(id);
request.onsuccess = function(event) {
console.log('数据删除成功');
};
request.onerror = function(event) {
console.error('删除失败:', event.target.error);
};
}
function deleteByCursor(db) {
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
const request = objectStore.openCursor();
request.onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
// 删除当前游标位置的数据
cursor.delete();
cursor.continue();
} else {
console.log('删除完成');
}
};
}
function clearStore(db) {
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
const request = objectStore.clear();
request.onsuccess = function(event) {
console.log('对象存储已清空');
};
}
function rangeQuery(db) {
const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const index = objectStore.index('age');
// 创建范围:年龄在20到30之间
const range = IDBKeyRange.bound(20, 30);
const request = index.openCursor(range);
request.onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
console.log('用户:', cursor.value);
cursor.continue();
} else {
console.log('查询完成');
}
};
}
| 方法 | 说明 | 示例 |
|---|---|---|
bound(lower, upper, lowerOpen, upperOpen) |
范围查询 | IDBKeyRange.bound(20, 30) |
only(value) |
精确匹配 | IDBKeyRange.only(25) |
lowerBound(lower, open) |
大于等于 | IDBKeyRange.lowerBound(20) |
upperBound(upper, open) |
小于等于 | IDBKeyRange.upperBound(30) |
function sortData(db) {
const transaction = db.transaction(['users'], 'readonly');
const objectStore = transaction.objectStore('users');
const index = objectStore.index('age');
// 升序(默认)
const request = index.openCursor();
// 降序
// const request = index.openCursor(null, 'prev');
request.onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
console.log('年龄:', cursor.value.age);
cursor.continue();
}
};
}
| 模式 | 说明 |
|---|---|
readonly |
只读模式(默认) |
readwrite |
读写模式 |
versionchange |
版本变更模式 |
function transactionExample(db) {
const transaction = db.transaction(['users'], 'readwrite');
const objectStore = transaction.objectStore('users');
// 事务完成
transaction.oncomplete = function(event) {
console.log('事务完成');
};
// 事务错误
transaction.onerror = function(event) {
console.error('事务错误:', event.target.error);
};
// 事务中止
transaction.onabort = function(event) {
console.log('事务中止');
};
// 添加多个数据
objectStore.add({ name: '张三', age: 25 });
objectStore.add({ name: '李四', age: 30 });
}
东巴文点评:事务是IndexedDB保证数据一致性的核心机制,所有数据操作都应该在事务中进行。
class IndexedDBUtil {
constructor(dbName, version = 1) {
this.dbName = dbName;
this.version = version;
this.db = null;
}
// 打开数据库
open(storeConfig) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version);
request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result;
resolve(this.db);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建对象存储
storeConfig.forEach(config => {
if (!db.objectStoreNames.contains(config.name)) {
const store = db.createObjectStore(config.name, config.options);
// 创建索引
if (config.indexes) {
config.indexes.forEach(index => {
store.createIndex(index.name, index.keyPath, index.options);
});
}
}
});
};
});
}
// 添加数据
add(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.add(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 更新数据
put(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.put(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 获取数据
get(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const request = store.get(key);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 获取所有数据
getAll(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 删除数据
delete(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.delete(key);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
// 清空对象存储
clear(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.clear();
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
// 通过索引查询
getByIndex(storeName, indexName, value) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const index = store.index(indexName);
const request = index.get(value);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 关闭数据库
close() {
if (this.db) {
this.db.close();
this.db = null;
}
}
}
// 使用示例
const dbUtil = new IndexedDBUtil('myDatabase', 1);
// 配置对象存储
const storeConfig = [
{
name: 'users',
options: { keyPath: 'id', autoIncrement: true },
indexes: [
{ name: 'email', keyPath: 'email', options: { unique: true } },
{ name: 'name', keyPath: 'name', options: { unique: false } }
]
}
];
// 打开数据库
dbUtil.open(storeConfig).then(() => {
console.log('数据库打开成功');
// 添加数据
return dbUtil.add('users', {
name: '张三',
email: 'zhangsan@example.com',
age: 25
});
}).then(id => {
console.log('数据添加成功,ID:', id);
// 获取数据
return dbUtil.get('users', id);
}).then(user => {
console.log('用户信息:', user);
});
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IndexedDB示例 - 东巴文</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.section {
margin: 20px 0;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
}
.user-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
margin: 10px 0;
background: #f5f5f5;
border-radius: 3px;
}
input {
padding: 8px;
margin: 5px;
border: 1px solid #ddd;
border-radius: 3px;
}
button {
padding: 8px 16px;
margin: 5px;
border: none;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 3px;
cursor: pointer;
}
button:hover {
opacity: 0.9;
}
.stats {
display: flex;
gap: 20px;
margin: 20px 0;
}
.stat-item {
flex: 1;
padding: 15px;
background: #f5f5f5;
border-radius: 5px;
text-align: center;
}
</style>
</head>
<body>
<h1>IndexedDB示例</h1>
<div class="stats">
<div class="stat-item">
<h3>数据库状态</h3>
<p id="dbStatus">未连接</p>
</div>
<div class="stat-item">
<h3>用户数量</h3>
<p id="userCount">0</p>
</div>
</div>
<div class="section">
<h2>添加用户</h2>
<input type="text" id="nameInput" placeholder="姓名">
<input type="email" id="emailInput" placeholder="邮箱">
<input type="number" id="ageInput" placeholder="年龄">
<button onclick="addUser()">添加用户</button>
</div>
<div class="section">
<h2>用户列表</h2>
<div id="userList"></div>
<button onclick="loadUsers()">刷新列表</button>
<button onclick="clearUsers()">清空所有</button>
</div>
<div class="section">
<h2>搜索用户</h2>
<input type="text" id="searchInput" placeholder="输入邮箱搜索">
<button onclick="searchUser()">搜索</button>
<div id="searchResult"></div>
</div>
<script>
class IndexedDBUtil {
constructor(dbName, version = 1) {
this.dbName = dbName;
this.version = version;
this.db = null;
}
open(storeConfig) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version);
request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result;
resolve(this.db);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
storeConfig.forEach(config => {
if (!db.objectStoreNames.contains(config.name)) {
const store = db.createObjectStore(config.name, config.options);
if (config.indexes) {
config.indexes.forEach(index => {
store.createIndex(index.name, index.keyPath, index.options);
});
}
}
});
};
});
}
add(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.add(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
put(storeName, data) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.put(data);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
get(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const request = store.get(key);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
getAll(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
delete(storeName, key) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.delete(key);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
clear(storeName) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const request = store.clear();
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
getByIndex(storeName, indexName, value) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction([storeName], 'readonly');
const store = transaction.objectStore(storeName);
const index = store.index(indexName);
const request = index.get(value);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
}
const dbUtil = new IndexedDBUtil('UserDatabase', 1);
const storeConfig = [
{
name: 'users',
options: { keyPath: 'id', autoIncrement: true },
indexes: [
{ name: 'email', keyPath: 'email', options: { unique: true } },
{ name: 'name', keyPath: 'name', options: { unique: false } }
]
}
];
// 初始化数据库
dbUtil.open(storeConfig).then(() => {
document.getElementById('dbStatus').textContent = '已连接';
loadUsers();
}).catch(error => {
console.error('数据库打开失败:', error);
document.getElementById('dbStatus').textContent = '连接失败';
});
// 添加用户
async function addUser() {
const name = document.getElementById('nameInput').value.trim();
const email = document.getElementById('emailInput').value.trim();
const age = parseInt(document.getElementById('ageInput').value);
if (!name || !email || !age) {
alert('请填写完整信息');
return;
}
try {
await dbUtil.add('users', { name, email, age });
alert('添加成功');
// 清空输入框
document.getElementById('nameInput').value = '';
document.getElementById('emailInput').value = '';
document.getElementById('ageInput').value = '';
// 刷新列表
loadUsers();
} catch (error) {
console.error('添加失败:', error);
alert('添加失败: ' + error.message);
}
}
// 加载用户列表
async function loadUsers() {
try {
const users = await dbUtil.getAll('users');
const userListEl = document.getElementById('userList');
userListEl.innerHTML = users.map(user => `
<div class="user-item">
<span><strong>${user.name}</strong> (${user.email}) - ${user.age}岁</span>
<button onclick="deleteUser(${user.id})">删除</button>
</div>
`).join('');
document.getElementById('userCount').textContent = users.length;
} catch (error) {
console.error('加载失败:', error);
}
}
// 删除用户
async function deleteUser(id) {
if (confirm('确定删除此用户?')) {
try {
await dbUtil.delete('users', id);
alert('删除成功');
loadUsers();
} catch (error) {
console.error('删除失败:', error);
alert('删除失败: ' + error.message);
}
}
}
// 清空所有用户
async function clearUsers() {
if (confirm('确定清空所有用户?')) {
try {
await dbUtil.clear('users');
alert('清空成功');
loadUsers();
} catch (error) {
console.error('清空失败:', error);
alert('清空失败: ' + error.message);
}
}
}
// 搜索用户
async function searchUser() {
const email = document.getElementById('searchInput').value.trim();
if (!email) {
alert('请输入邮箱');
return;
}
try {
const user = await dbUtil.getByIndex('users', 'email', email);
const resultEl = document.getElementById('searchResult');
if (user) {
resultEl.innerHTML = `
<div class="user-item">
<span><strong>${user.name}</strong> (${user.email}) - ${user.age}岁</span>
</div>
`;
} else {
resultEl.innerHTML = '<p>未找到用户</p>';
}
} catch (error) {
console.error('搜索失败:', error);
alert('搜索失败: ' + error.message);
}
}
</script>
</body>
</html>
// 推荐:始终处理错误
async function safeAdd(dbUtil, storeName, data) {
try {
const id = await dbUtil.add(storeName, data);
console.log('添加成功:', id);
return id;
} catch (error) {
console.error('添加失败:', error);
throw error;
}
}
// 不推荐:不处理错误
dbUtil.add('users', data).then(id => {
console.log('添加成功:', id);
});
function validateUser(user) {
if (!user.name || user.name.trim() === '') {
throw new Error('姓名不能为空');
}
if (!user.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(user.email)) {
throw new Error('邮箱格式不正确');
}
if (!user.age || user.age < 0 || user.age > 150) {
throw new Error('年龄必须在0-150之间');
}
return true;
}
async function addUser(user) {
validateUser(user);
return await dbUtil.add('users', user);
}
async function batchAdd(users) {
const transaction = dbUtil.db.transaction(['users'], 'readwrite');
const store = transaction.objectStore('users');
const promises = users.map(user => {
return new Promise((resolve, reject) => {
const request = store.add(user);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
});
return Promise.all(promises);
}
问题1:IndexedDB中用于创建对象存储的方法是?
A. createStore()
B. createObjectStore()
C. addObjectStore()
D. newObjectStore()
答案:B
东巴文解释:在onupgradeneeded事件中,使用db.createObjectStore()方法创建对象存储。
问题2:IndexedDB的事务模式不包括以下哪种?
A. readonly
B. readwrite
C. versionchange
D. readwriteall
答案:D
东巴文解释:IndexedDB支持三种事务模式:readonly(只读)、readwrite(读写)、versionchange(版本变更)。
任务:创建一个IndexedDB数据库,存储书籍信息(书名、作者、ISBN、价格),实现添加、查询、删除功能。
<details> <summary>点击查看参考答案</summary><!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>书籍管理</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 50px auto;
padding: 20px;
}
.book-item {
padding: 15px;
margin: 10px 0;
background: #f5f5f5;
border-radius: 5px;
}
input {
padding: 8px;
margin: 5px;
border: 1px solid #ddd;
border-radius: 3px;
}
button {
padding: 8px 16px;
margin: 5px;
border: none;
background: #667eea;
color: white;
border-radius: 3px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>书籍管理</h1>
<div>
<h2>添加书籍</h2>
<input type="text" id="title" placeholder="书名">
<input type="text" id="author" placeholder="作者">
<input type="text" id="isbn" placeholder="ISBN">
<input type="number" id="price" placeholder="价格">
<button onclick="addBook()">添加</button>
</div>
<div>
<h2>书籍列表</h2>
<div id="bookList"></div>
</div>
<script>
class BookDB {
constructor() {
this.db = null;
}
open() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('BookDatabase', 1);
request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result;
resolve(this.db);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('books', { keyPath: 'isbn' });
store.createIndex('title', 'title', { unique: false });
store.createIndex('author', 'author', { unique: false });
};
});
}
add(book) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['books'], 'readwrite');
const store = transaction.objectStore('books');
const request = store.add(book);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
getAll() {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['books'], 'readonly');
const store = transaction.objectStore('books');
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
delete(isbn) {
return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['books'], 'readwrite');
const store = transaction.objectStore('books');
const request = store.delete(isbn);
request.onsuccess = () => resolve();
request.onerror = () => reject(request.error);
});
}
}
const bookDB = new BookDB();
bookDB.open().then(() => {
console.log('数据库打开成功');
loadBooks();
}).catch(error => {
console.error('数据库打开失败:', error);
});
async function addBook() {
const title = document.getElementById('title').value.trim();
const author = document.getElementById('author').value.trim();
const isbn = document.getElementById('isbn').value.trim();
const price = parseFloat(document.getElementById('price').value);
if (!title || !author || !isbn || !price) {
alert('请填写完整信息');
return;
}
try {
await bookDB.add({ title, author, isbn, price });
alert('添加成功');
loadBooks();
} catch (error) {
console.error('添加失败:', error);
alert('添加失败: ' + error.message);
}
}
async function loadBooks() {
try {
const books = await bookDB.getAll();
const listEl = document.getElementById('bookList');
listEl.innerHTML = books.map(book => `
<div class="book-item">
<h3>${book.title}</h3>
<p>作者: ${book.author}</p>
<p>ISBN: ${book.isbn}</p>
<p>价格: ¥${book.price}</p>
<button onclick="deleteBook('${book.isbn}')">删除</button>
</div>
`).join('');
} catch (error) {
console.error('加载失败:', error);
}
}
async function deleteBook(isbn) {
if (confirm('确定删除此书籍?')) {
try {
await bookDB.delete(isbn);
alert('删除成功');
loadBooks();
} catch (error) {
console.error('删除失败:', error);
alert('删除失败: ' + error.message);
}
}
}
</script>
</body>
</html>
</details>
东巴文(db-w.cn) - 让编程学习更有趣、更高效!