闲来无事学习一下indexedDB,看前提示,我这不是学习文档,我只是把我学习的成果代码跟大家分享一下,因为我自己看文档的代码偶尔也会困惑,边写边理解,我这个代码只是给刚接触indexedDB的人一点提示。
一、学习文档
1、学习前端知识首选:MDN--indexedDB文档https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Using_IndexedDB
2、阮一峰老师的分享文档:浏览器数据库 IndexedDB 入门教程 - 阮一峰的网络日志
3、官方API文档,纯英文,不过提供的代码很有用:Indexed Database API 3.0
我提供的代码只是在你看完这些东西之后,提供一点提示
二、代码
这是最终效果
效果有点难看,将就一下吧
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="./css/indexedDB.css" rel="stylesheet">
</head>
<body>
<div class="add_data area">
<input type="text" id="name" placeholder="名字">
<input type="text" id="phone" placeholder="手机号码">
<button onclick="addData()">增加数据</button>
<span class="status"></span>
</div>
<div class="get_data area">
<input type="text" id="search" placeholder="输入主键">
<button onclick="getData()">查询数据</button>
<button onclick="deleteData()">删除数据</button>
<span class="status"></span>
</div>
<div class="get_all_data area">
<button onclick="getAllData()">查询所有数据</button>
<span class="status"></span>
</div>
<div class="edit_data area">
<input type="text" id="edit_id" placeholder="修改ID">
<input type="text" id="edit_name" placeholder="修改姓名">
<input type="text" id="edit_phone" placeholder="修改手机">
<button onclick="getEditData()">查询数据</button>
<button onclick="editData()">修改数据</button>
<span class="status"></span>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="./js/indexedDB.js"></script>
</body>
</html>
JS
var ctrlDB; // 公共变量,存储数据库表
window.onload = function () {
if (!window.indexedDB) {
alert('不支持IndexedDB');
} else {
var idb = window.indexedDB;
var request = idb.open('TestDataBase');
request.onerror = function (event) {
console.error('Database error: ' + event.target.errorCode);
}
request.onsuccess = function (event) {
ctrlDB = event.target.result;
}
request.onupgradeneeded = function (event) {
var db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('persons')) {
objectStore = db.createObjectStore('persons', { autoIncrement: true });
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('phone', 'phone', { unique: true });
}
}
}
}
// 新增数据
function addData () {
var customerOS = ctrlDB.transaction(['persons'], 'readwrite').objectStore('persons');
var data = {
name: $('#name').val() || null,
phone: $('#phone').val() || null
};
var request = customerOS.add(data);
request.onsuccess = function () {
$('#name').val('')
$('#phone').val('')
$('.add_data .status').text('数据已新增');
}
request.onerror = function () {
$('.add_data .status').text('数据新增失败');
}
}
// 获取单个数据
function getData () {
var customerOS = ctrlDB.transaction(['persons'], 'readwrite').objectStore('persons');
var request = customerOS.get(parseInt($('#search').val()));
var getDataDiv = $('.get_data');
request.onsuccess = function () {
var result = request.result;
console.log('数据: ' + result);
getDataDiv.find('.data_div').remove();
if (result) {
getDataDiv.find('.status').text('数据已获取');
createDataDiv('.get_data', result.name, result.phone);
} else {
getDataDiv.find('.status').text('数据不存在');
}
return result;
}
request.onerror = function () {
getDataDiv.find('.status').text('数据获取失败');
}
}
// 获取所有数据
function getAllData () {
var customerOS = ctrlDB.transaction(['persons'], 'readwrite').objectStore('persons');
var dataArr = [];
$('.get_all_data').find('.data_div').remove();
customerOS.openCursor().onsuccess = function (event) {
var result = event.target.result;
if (result) {
console.log('result: ', result);
dataArr.push(result.value);
createDataDiv('.get_all_data', result.value.name, result.value.phone);
result.continue();
}
console.log(dataArr);
return dataArr;
}
}
// 创建数据展示DIV
function createDataDiv (elem, name, phone) {
var dataDiv = $('<div></div>').addClass('data_div');
dataDiv.append($('<p></p>').text('姓名:' + name));
dataDiv.append($('<p></p>').text('手机:' + phone));
$(elem).append(dataDiv);
}
// 删除当前数据
function deleteData () {
var customerOS = ctrlDB.transaction(['persons'], 'readwrite').objectStore('persons');
var request = customerOS.delete(parseInt($('#search').val()));
request.onsuccess = function () {
$('.get_data .status').text('数据已删除');
}
request.onerror = function () {
$('.get_data .status').text('数据删除失败');
}
}
// 获取要修改的数据,和获取单个数据一致,只是改了输入框位置
function getEditData () {
var customerOS = ctrlDB.transaction(['persons'], 'readwrite').objectStore('persons');
var request = customerOS.get(parseInt($('#edit_id').val()));
var getDataDiv = $('.edit_data');
request.onsuccess = function () {
var result = request.result;
if (result) {
getDataDiv.find('.status').text('数据已获取');
$('#edit_name').val(result.name);
$('#edit_phone').val(result.phone);
} else {
getDataDiv.find('.status').text('数据不存在');
}
return result;
}
request.onerror = function () {
getDataDiv.find('.status').text('数据获取失败');
}
}
// 修改数据
function editData () {
var customerOS = ctrlDB.transaction(['persons'], 'readwrite').objectStore('persons');
var data = {
name: $('#edit_name').val() || null,
phone: $('#edit_phone').val() || null
}
var request = customerOS.put(data, parseInt($('#edit_id').val())); // 自动设置主键的情况下更新数据需要传入当前主键的值才能更新数据,注意与设置了keyPath区分
request.onsuccess = function () {
$('#edit_name').val('')
$('#edit_phone').val('')
$('.edit_data .status').text('数据已修改');
}
request.onerror = function () {
$('.edit_data .status').text('数据修改失败');
}
}
至于CSS代码就没什么必要了,随便写写就行
三、我学习时遇到的一些问题
1、Uncaught DOMException: Failed to execute 'createObjectStore' on 'IDBDatabase': The database is not running a version change transaction
遇到这个错误在刚开始创建数据库时没用心看示例代码出现的问题,讲创建数据库的操作写在了onsuccess里
var idb = window.indexedDB;
var request = idb.open('TestDataBase');
request.onerror = function (event) {
console.error('Database error: ' + event.target.errorCode);
}
request.onsuccess = function (event) {
ctrlDB = event.target.result;
/* 错误写法,不能写在这里要写在onupgradeneeded里
objectStore = ctrlDB.createObjectStore('persons', { autoIncrement: true });
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('phone', 'phone', { unique: true });
*/
}
request.onupgradeneeded = function (event) {
var db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('persons')) {
objectStore = db.createObjectStore('persons', { autoIncrement: true });
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('phone', 'phone', { unique: true });
}
}
2、有关var customerOS = ctrlDB.transaction(['persons'], 'readwrite').objectStore('persons');
仔细看的话增删改查每种操作都会有这一句,所以我自然而然的想把这个当成公共变量,结果会报错的
Failed to execute 'add' on 'IDBObjectStore': The transaction has finished.
简单理解就能明白transaction结束了,不能继续使用,所以才需要每次操作数据库都要获得一个,我才使用了ctrlDB这个公共变量
3、主键使用键生成器时,修改操作的区别
var objStore = db.createObjectStore("names", { autoIncrement : true }); // 键生成器
var objectStore = db.createObjectStore("customers", { keyPath: "id" }); // 自己设置主键与主键值,主键值唯一不可为空
我当时偷懒直接用了键生成器来生成主键,表是这样的
注意此时的key值(红色标注处)和自己设置主键是不一样的
然后在使用put方法更新数据时,网上提供的大部分例子都没用键生成器,所以我使用文档给的例子更新数据不是失败(这种情况是因为设置phone为唯一值,修改时没改手机号)就是新增了一个值
解决这个问题是在官方的文档上提供了
store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // Will get key 1
store.put("b", 3); // Will use key 3,关键在此处
store.put("c"); // Will get key 4
store.put("d", -10); // Will use key -10
store.put("e"); // Will get key 5
store.put("f", 6.00001); // Will use key 6.0001
store.put("g"); // Will get key 7
store.put("f", 8.9999); // Will use key 8.9999
store.put("g"); // Will get key 9
store.put("h", "foo"); // Will use key "foo"
store.put("i"); // Will get key 10
store.put("j", [1000]); // Will use key [1000]
store.put("k"); // Will get key 11
// All of these would behave the same if the objectStore used a
// keyPath and the explicit key was passed inline in the object
除此之外学习过程还是比较顺利的,也算对indexedDB有了一点了解,这玩意在我现在的工作经历里也不知道在那用,不过多学一点总没错的