一、IndexedDB 1、簡介 隨著瀏覽器功能增強,許多網站開始將大量數據保存在客戶端,從而減少從伺服器獲取數據的操作,提高了響應速度。 cookie 由於大小不超過 4kb,肯定不合適。 LocalStorage 大小在 2.5 - 10 M間(不同瀏覽器不同,比如Chrome為 5M),且不提 ...
一、IndexedDB
1、簡介
隨著瀏覽器功能增強,許多網站開始將大量數據保存在客戶端,從而減少從伺服器獲取數據的操作,提高了響應速度。
cookie 由於大小不超過 4kb,肯定不合適。
LocalStorage 大小在 2.5 - 10 M間(不同瀏覽器不同,比如Chrome為 5M),且不提供索引、查找慢,也不合適。
IndexedDB 就比較合適了,是瀏覽器提供的本地資料庫,它可以被網頁腳本創建和操作。IndexedDB 允許儲存大量數據,提供查找介面,還能建立索引提高查詢效率。
2、特點
(1)採用鍵值對存儲。
IndexedDB 內部採用對象倉庫(object store)存放數據。所有類型的數據都可以直接存入,包括 JavaScript 對象。對象倉庫中,數據以"鍵值對"的形式保存。
(2)非同步處理。
IndexedDB 操作時採用非同步處理,用戶可以進行其它操作。
(3)支持事務。
IndexedDB 支持事務,即要麼完成、要麼失敗,不會出現完成一半的狀態。
(4)存儲空間大、且支持二進位存儲。
3、相關概念
(1)資料庫(IDBDatabase 對象)
管理、存儲數據的倉庫。IndexedDB 資料庫有版本的概念。同一個時刻,只能有一個版本的資料庫存在。如果要修改資料庫結構(新增或刪除表、索引或者主鍵),只能通過升級資料庫版本完成。
(2)對象倉庫(IDBObjectStore 對象)
每個資料庫都包含若幹對象倉庫。可以理解為一個個數據表。
(3)數據記錄
對象倉庫中存儲的即為數據記錄,採用鍵值對保存。其中鍵唯一,值可以為任意類型。
(4)索引(IDBIndex 對象)
為了提高查詢效率,可以根據數據記錄的主鍵建立索引。
(5)事務(IDBTransaction 對象)
數據記錄的讀寫和刪改,都要通過事務完成。事務對象提供error、abort和complete三個事件,用來監聽操作結果。
(6)操作請求(IDBRequest 對象)
(7)指針( IDBCursor 對象)
可用於遍曆數據。
(8)主鍵集合(IDBKeyRange 對象)
4、vue使用indexedDB快速入門實例
(1)項目目錄結構
使用vue-cli創建項目。參考:https://www.cnblogs.com/l-y-h/p/11241503.html
(2)完整代碼
此處,我將創建一個 “test” 資料庫, 其中有一個 “person” 表(對象倉庫) 【main.js】 import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app') 【App.vue】 <template> <div> <small>添加前請先打開資料庫(如資料庫不存在則執行創建過程)</small><br /><br /> <button @click="openDB">打開資料庫</button> <button @click="deleteDB">刪除資料庫</button><br /><br /> <button @click="closeDB">關閉資料庫</button><br /><br /> 姓名:<input type="text" id="name" v-model="name"><br /> 年齡:<input type="number" id="age" min=1 v-model="age"><br /> 性別: 男:<input type="radio" id="man" name="sex" value="male" v-model="sex"> 女:<input type="radio" id="woman" name="sex" value="female" v-model="sex"><br /> <button @click="add">添加數據</button> <button @click="get">獲取數據</button><br /> <button @click="foreach">遍曆數據</button><br /> <button @click="update">更新數據</button><br /> <button @click="remove">刪除數據</button><br /> <button @click="searchFromIndex">根據索引查數據</button><br /> </div> <!--App --> </template> <script> import indexedDB from './indexedDB.js' export default { data () { return { name: 'tom', age: '12', sex: 'male' } }, methods: { openDB() { indexedDB.openDB('test', 'person', 1) }, deleteDB() { indexedDB.deleteDB('test') }, closeDB() { indexedDB.closeDB('test') }, add() { indexedDB.add('person', {name: this.name, age: this.age, sex: this.sex}) }, get() { indexedDB.get('person') }, foreach() { indexedDB.foreach('person') }, update() { indexedDB.update('person', {id: 4, name: this.name, age: this.age, sex: this.sex}) }, remove() { indexedDB.remove('person', 4) }, searchFromIndex() { indexedDB.searchFromIndex('person', 'name', 'tom') } } } </script> <style> </style> 【indexedDB.js】 // 定義一個全局變數,用於保存資料庫連接(開發中應該不會這麼寫,此處只是幫助理解) let db = null; export default { // indexedDB相容 indexedDB: window.indexedDB || window.webkitindexedDB || window.msIndexedDB || mozIndexedDB, // 打開資料庫 // dbname指的是 資料庫名, version 指的是 版本號 openDB(dbname, objectStoreName, version) { // 獲取當前資料庫版本號 var version = version || 1 // 獲取資料庫連接,若資料庫不存在,會創建資料庫(非同步處理,根據情況自動觸發下麵三個事件) var request = this.indexedDB.open(dbname, version) // 獲取資料庫連接失敗 request.onerror = function(event) { console.log('IndexedDB資料庫打開錯誤') } // 獲取資料庫連接成功 request.onsuccess = function(event, callback) { db = event.target.result; if (callback && (typeof callback === 'function')) { callback(db) } if (db != null) { console.log('資料庫打開成功') } } // 創建新的儲存空間(當第一次創建資料庫、或者資料庫版本號變化時會觸發) request.onupgradeneeded = function(event) { console.log('資料庫版本變化') console.log('創建資料庫' + dbname) // 拿到資料庫連接的結果對象 db = event.target.result; // 判斷當前資料庫中表(對象倉庫)是否存在(註意此處是資料庫的表名,不是資料庫名) if (!db.objectStoreNames.contains(objectStoreName)) { // 創建對象倉庫,並設置主鍵自增 var objectStore = db.createObjectStore(objectStoreName, { keyPath: 'id', autoIncrement: true }) // 創建索引(根據需要創建) objectStore.createIndex('name', 'name', { unique: false }) objectStore.createIndex('age', 'age', { unique: false }) objectStore.createIndex('sex', 'sex', { unique: false }) } } }, // 刪除資料庫 deleteDB: function(dbname, callback) { // 刪除資料庫 var deleteQuest = this.indexedDB.deleteDatabase(dbname); // 成功刪除 deleteQuest.onerror = function() { console.log('刪除資料庫出錯' + event.target.message) } // 刪除失敗 deleteQuest.onsuccess = function() { if (callback && (typeof callback === 'function')) { callback() } console.log('刪除資料庫成功') } }, // 關閉資料庫 closeDB: function() { if (db != null) { db.close() db = null console.log("資料庫關閉") } }, // 添加數據 // 對象倉庫(表名),傳入的參數 add: function(objectStoreName, argument) { if (db != null) { console.log(db) // 執行事務,添加數據到對象倉庫(表) var request = db.transaction([objectStoreName], 'readwrite') .objectStore(objectStoreName) .add(argument); request.onsuccess = function(event) { console.log('數據寫入成功'); }; request.onerror = function(event) { console.log('數據寫入失敗'); } } }, // 獲取數據 // 對象倉庫(表名) get: function(objectStoreName) { if (db != null){ console.log(db) // 執行事務,從對象倉庫(表)中獲取所有數據 var request = db.transaction([objectStoreName], 'readwrite') .objectStore(objectStoreName).getAll() // 數據獲取失敗 request.onerror = function(event) { console.log('事務失敗') } //數據獲取成功 request.onsuccess = function(event) { if (request.result) { // 列印所有數據 console.log(request.result) } else { console.log('未獲得數據記錄') } }; } }, // 遍曆數據 // 對象倉庫(表名) foreach: function(objectStoreName) { if (db != null){ console.log(db) // 執行事務,從對象倉庫(表)中獲取所有數據 var request = db.transaction([objectStoreName], 'readwrite') .objectStore(objectStoreName).openCursor() // 數據獲取失敗 request.onerror = function(event) { console.log('事務失敗') } //數據獲取成功 request.onsuccess = function(event) { let cursor = request.result if (cursor) { // 遍歷列印所有數據 console.log(cursor) console.log(cursor.key) console.log(cursor.value.name) console.log(cursor.value.age) console.log(cursor.value.sex) cursor.continue() } else { console.log('未獲得數據記錄') } }; } }, // 更新數據(若數據存在,則覆蓋之前的數據,若數據不存在,則新增一個值) // 對象倉庫(表名) update: function(objectStoreName, argument) { if (db != null) { console.log(db) // 執行事務,添加數據到對象倉庫(表) var request = db.transaction([objectStoreName], 'readwrite') .objectStore(objectStoreName) .put(argument); request.onsuccess = function(event) { console.log('數據更新成功'); }; request.onerror = function(event) { console.log('數據更新失敗'); } } }, // 刪除數據(若數據不存在,則不會執行刪除操作) // 對象倉庫(表名) remove: function(objectStoreName, index) { if (db != null){ console.log(db) // 執行事務,從對象倉庫(表)中獲取所有數據 var request = db.transaction([objectStoreName], 'readwrite') .objectStore(objectStoreName).delete(index) // 數據獲取失敗 request.onerror = function(event) { console.log('事務失敗') } //數據獲取成功 request.onsuccess = function(event) { if (request.result) { // 遍歷列印所有數據 console.log(request.result) } else { console.log('未獲得數據記錄') } }; } }, // 根據索引查值(若數據不存在,返回一個[]數組) // 對象倉庫(表名) searchFromIndex: function(objectStoreName, index, data) { if (db != null){ console.log(db) // 執行事務,從對象倉庫(表)中獲取所有數據 var request = db.transaction([objectStoreName], 'readonly') .objectStore(objectStoreName).index(index).getAll(data) // 數據獲取失敗 request.onerror = function(event) { console.log('事務失敗') } //數據獲取成功 request.onsuccess = function(event) { if (request.result) { // 遍歷列印所有數據 console.log(request.result) } else { console.log('未獲得數據記錄') } }; } } }
(3)截圖:
step1:初始化頁面。
step2:點擊 打開資料庫。
step3:點擊添加按鈕
step4:改變數據後,再次添加
step5:獲取數據(控制台列印)
step6:點擊遍曆數據按鈕
step7:更新數據
以更新id=4為例,此時數據不存在,會新增。
當修改數據後,再次更新,則會覆蓋原數據。
step8:根據 name 查詢所有 為 tom 的數據。
step9:刪除第4條數據(根據主鍵來刪,若主鍵不存在,則不會刪除)。
先獲取當前數據。
執行刪除後,會刪除id=4(id是主鍵)的數據。
step10:關閉、刪除資料庫
若先點擊 刪除按鈕,再點擊關閉按鈕,則刪除按鈕會等關閉按鈕執行後再執行。
此時,test資料庫被刪除。
(4)創建、打開資料庫
需使用 indexedDB.open() 方法,返回一個 IDBRequest 對象,並可能觸發三個事件(onsuccess 、onerror、onupgradeneeded )。
【格式:】
var request = window.indexedDB.open(databaseName, version);
【其中:】
databaseName :為字元串,表示資料庫名,不可省略。
version : 為當前資料庫版本,當資料庫不存在時,會創建資料庫,且預設為1。
當資料庫存在時,若 version 大於當前資料庫版本,則會觸發資料庫升級操作。
當version 省略時,預設為當前資料庫版本。
【可能會觸發的事件】
onsuccess 表示成功打開資料庫。
onerror 表示打開資料庫失敗。
onupgradeneeded 表示資料庫升級事件。當資料庫不存在,或者資料庫指定版本號大於當前版本時觸發。
【代碼:】
// 打開資料庫
// dbname指的是 資料庫名, version 指的是 版本號
openDB(dbname, objectStoreName, version) {
// 獲取當前資料庫版本號
var version = version || 1
// 獲取資料庫連接,若資料庫不存在,會創建資料庫(非同步處理,根據情況自動觸發下麵三個事件)
var request = this.indexedDB.open(dbname, version)
// 獲取資料庫連接失敗
request.onerror = function(event) {
console.log('IndexedDB資料庫打開錯誤')
}
// 獲取資料庫連接成功
request.onsuccess = function(event, callback) {
db = event.target.result;
if (callback && (typeof callback === 'function')) {
callback(db)
}
if (db != null) {
console.log('資料庫打開成功')
}
}
// 創建新的儲存空間(當第一次創建資料庫、或者資料庫版本號變化時會觸發)
request.onupgradeneeded = function(event) {
console.log('資料庫版本變化')
console.log('創建資料庫' + dbname)
// 拿到資料庫連接的結果對象
db = event.target.result;
// 判斷當前資料庫中表(對象倉庫)是否存在(註意此處是資料庫的表名,不是資料庫名)
if (!db.objectStoreNames.contains(objectStoreName)) {
// 創建對象倉庫,並設置主鍵自增
var objectStore = db.createObjectStore(objectStoreName, {
keyPath: 'id',
autoIncrement: true
})
// 創建索引(根據需要創建)
objectStore.createIndex('name', 'name', {
unique: false
})
objectStore.createIndex('age', 'age', {
unique: false
})
objectStore.createIndex('sex', 'sex', {
unique: false
})
}
}
}
(5)添加數據
向對象倉庫(表)中寫入數據記錄。需要通過事務完成。
註意:
db之前已經聲明過全局了,這裡直接用(實際開發中應該不允許直接聲明,可以通過回調函數來實現,有時間再補充)。
創建一個事務需要根據 對象倉庫名(表名)以及操作模式(readwrite, readonly),創建事務後,通過IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 對象,再通過表格對象的add()方法,向表格寫入一條記錄。
// 添加數據
// 對象倉庫(表名),傳入的參數
add: function(objectStoreName, argument) {
if (db != null) {
console.log(db)
// 執行事務,添加數據到對象倉庫(表)
var request = db.transaction([objectStoreName], 'readwrite')
.objectStore(objectStoreName)
.add(argument);
request.onsuccess = function(event) {
console.log('數據寫入成功');
};
request.onerror = function(event) {
console.log('數據寫入失敗');
}
}
},
(6)讀取數據
需要事務來操作。
可以objectStore.get(index)、objectStore.getAll()方法用於讀取數據,參數index是主鍵的值。
// 獲取數據
// 對象倉庫(表名)
get: function(objectStoreName) {
if (db != null){
console.log(db)
// 執行事務,從對象倉庫(表)中獲取所有數據
var request = db.transaction([objectStoreName], 'readwrite')
.objectStore(objectStoreName).getAll()
// 數據獲取失敗
request.onerror = function(event) {
console.log('事務失敗')
}
//數據獲取成功
request.onsuccess = function(event) {
if (request.result) {
// 列印所有數據
console.log(request.result)
} else {
console.log('未獲得數據記錄')
}
};
}
},
(7)遍曆數據
需要事務來操作。
遍曆數據表格的所有記錄,要使用指針對象 IDBCursor,使用objectStore.openCursor()獲取。
// 遍曆數據
// 對象倉庫(表名)
foreach: function(objectStoreName) {
if (db != null){
console.log(db)
// 執行事務,從對象倉庫(表)中獲取所有數據
var request = db.transaction([objectStoreName], 'readwrite')
.objectStore(objectStoreName).openCursor()
// 數據獲取失敗
request.onerror = function(event) {
console.log('事務失敗')
}
//數據獲取成功
request.onsuccess = function(event) {
let cursor = request.result
if (cursor) {
// 遍歷列印所有數據
console.log(cursor)
console.log(cursor.key)
console.log(cursor.value.name)
console.log(cursor.value.age)
console.log(cursor.value.sex)
cursor.continue()
} else {
console.log('未獲得數據記錄')
}
};
}
},
(8)更新數據
需要事務來操作。
使用IDBObjectStore.put(index)方法可以更新數據,若index存在則覆蓋,否則新增一個值。
// 更新數據(若數據存在,則覆蓋之前的數據,若數據不存在,則新增一個值)
// 對象倉庫(表名)
update: function(objectStoreName, argument) {
if (db != null) {
console.log(db)
// 執行事務,添加數據到對象倉庫(表)
var request = db.transaction([objectStoreName], 'readwrite')
.objectStore(objectStoreName)
.put(argument);
request.onsuccess = function(event) {
console.log('數據更新成功');
};
request.onerror = function(event) {
console.log('數據更新失敗');
}
}
},
(9)刪除數據
需要事務來操作。
IDBObjectStore.delete(index)方法用於刪除記錄,參數index是主鍵的值。
// 刪除數據(若數據不存在,則不會執行刪除操作)
// 對象倉庫(表名)
remove: function(objectStoreName, index) {
if (db != null){
console.log(db)
// 執行事務,從對象倉庫(表)中獲取所有數據
var request = db.transaction([objectStoreName], 'readwrite')
.objectStore(objectStoreName).delete(index)
// 數據獲取失敗
request.onerror = function(event) {
console.log('事務失敗')
}
//數據獲取成功
request.onsuccess = function(event) {
if (request.result) {
// 遍歷列印所有數據
console.log(request.result)
} else {
console.log('未獲得數據記錄')
}
};
}
},
(10)使用索引
需要事務來操作。
根據建立的索引可以很方便的查值。IDBObjectStore.index(index)方法用於索引查找,參數index是索引的值。
// 根據索引查值(若數據不存在,返回一個[]數組)
// 對象倉庫(表名)
searchFromIndex: function(objectStoreName, index, data) {
if (db != null){
console.log(db)
// 執行事務,從對象倉庫(表)中獲取所有數據
var request = db.transaction([objectStoreName], 'readonly')
.objectStore(objectStoreName).index(index).getAll(data)
// 數據獲取失敗
request.onerror = function(event) {
console.log('事務失敗')
}
//數據獲取成功
request.onsuccess = function(event) {
if (request.result) {
// 遍歷列印所有數據
console.log(request.result)
} else {
console.log('未獲得數據記錄')
}
};
}
}
(11)刪除資料庫(會等事務結束再執行)
// 刪除資料庫
deleteDB: function(dbname, callback) {
// 刪除資料庫
var deleteQuest = this.indexedDB.deleteDatabase(dbname);
// 成功刪除
deleteQuest.onerror = function() {
console.log('刪除資料庫出錯' + event.target.message)
}
// 刪除失敗
deleteQuest.onsuccess = function() {
if (callback && (typeof callback === 'function')) {
callback()
}
console.log('刪除資料庫成功')
}
},
(12)關閉資料庫
// 關閉資料庫
closeDB: function() {
if (db != null) {
db.close()
db = null
console.log("資料庫關閉")
}
},
二、indexedDB常用方法
瀏覽器原生提供indexedDB對象,作為開發者的操作介面。
1、indexedDB.open()
用於打開資料庫。是一個非同步操作,但是會立即返回一個IDBOpenDBRequest 對象。
打開一個名為test、版本為1的資料庫。如果該資料庫不存在,則會新建該資料庫。
var openRequest = window.indexedDB.open('test', 1);
觸發事件:
success:打開成功。
error:打開失敗。
upgradeneeded:第一次打開該資料庫,或者資料庫版本發生變化。
在success中,可以通過openRequest.result屬性拿到已經打開的IndexedDB資料庫對象。
在upgradeneeded中,可以傳入event,通過 event.target.result 拿到已經打開的IndexedDB資料庫對象。
2、indexedDB.deleteDatabase()
用於刪除資料庫,是一個非同步操作,但會立刻返回一個IDBOpenDBRequest對象。
刪除名為test的資料庫。若資料庫不存在,不會報錯。
var DBDeleteRequest = window.indexedDB.deleteDatabase('test');
觸發事件:
success:刪除成功。
error:刪除失敗。
未完待續。。。
參考地址:
https://wangdoc.com/javascript/bom/indexeddb.html