IndexedDB æä¾äºå¨ç覽å¨ä¸å²åä¿çè³æçåè½ï¼èç±å®ï¼ä¸è«æ¯ç·ä¸æç·ä¸æåçæç¨é½å¯ä»¥é²è¡è³æååã
éæ¼æ¬ææ¬ææå¸¶é å使ä½é忥 IndexedDB ç APIï¼å¦æä¸ç¥éçéº¼æ¯ IndexedDBï¼è«å çç"IndexedDB åºæ¬ç¤å¿µ"ã
åºæ¬æä½æ¥é©æä½ IndexedDB çåºæ¬æ¥é©å»ºè°å¦ä¸:
好äºï¼ç¥éäºä¸è¿°æ¦å¿µå¾ï¼æåå¯ä»¥ä¾å¯¦éåäºç麼ã
建ç«åçµæ§è³æåº«ç±æ¼ IndexedDB çæ¨æºä»å¨æ¼é²ï¼æä»¥ç®åä¸äºå¯¦ä½ééè¦å ä¸ç覽å¨åç¶´æ¨ç¤º(å¦ Gecko åºç¤ç覽å¨çåç¶´æ¨ç¤ºçº mozï¼WebKit åºç¤ç覽å¨çåç¶´æ¨ç¤ºçº webkit)ï¼ç覽å¨ç實ä½ä¹å¯è½æææå·®ç°ï¼ä¸é䏿¦å ±èæ¨æºéæï¼ç¡ç覽å¨åç¶´æ¨ç¤ºå¯¦ä½å°åºç¾ãå ¶å¯¦ï¼Internet Explorer 10, Firefox 16, Chrome 24 å·²ç¶æäºç¡ç覽å¨åç¶´æ¨ç¤ºå¯¦ä½ã
æä½å¯¦é©æ§è³ªç IndexedDB妿éè¦è©¦é©ç覽å¨çåç¶´æ¨ç¤ºï¼å¯ä»¥å¦ä¸:
// In the following line, you should include the prefixes of implementations you want to test.
window.indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB;
// DON'T use "var indexedDB = ..." if you're not in a function.
// Moreover, you may need references to some window.IDB* objects:
window.IDBTransaction =
window.IDBTransaction ||
window.webkitIDBTransaction ||
window.msIDBTransaction;
window.IDBKeyRange =
window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)
è«æ³¨æç覽å¨åç¶´æ¨ç¤ºç實ä½å¯è½ä¸å®æ´ãæäºå顿ä»ç¶éµå®èçæ¨æºï¼å æ¤ä¸å»ºè°å¨æ£å¼çç¨å¼ç¢¼ä¸ä½¿ç¨ãèå ¶å®£ç¨±æ¯æ´åæåé¡ï¼åä¸å¦ç´æ¥ä¸æ¯æ´ã
if (!window.indexedDB) {
window.alert(
"Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.",
);
}
éåè³æåº«
éé å¦ä¸:
// Let us open our database
var request = window.indexedDB.open("MyTestDatabase", 3);
注æå°äºåï¼éåè³æåº«å¿ é è¦é²è¡è«æ±ã
éåè«æ±ä¸¦ä¸æç«å»éåè³æåº«æäº¤æï¼å¼å« open()æ¹æ³æåå³ä¸åIDBOpenDBRequest
ç©ä»¶ï¼éåç©ä»¶ææå
©åäºä»¶(success å error)ã大é¨å IndexedDB çé忥åè½é½æåå³ä¸åIDBDatabase
é¡ç©ä»¶ï¼ç¶å¾æåå¯ä»¥è¨»åæåå失æäºä»¶èçå¨ã
Open æ¹æ³ç¬¬äºå忏æ¯è³æåº«çæ¬ï¼è³æåº«çæ¬æ±ºå®äºè³æåº«çµæ§ï¼ä¹å°±æ¯è³æåº«ç©ä»¶åæªççµæ§ãå¦æè«æ±çæ¬ä¸åå¨(æ¯å¦å çºéæ¯ä¸åæ°è³æåº«ææ¯è³æåº«çæ¬å·²åç´)ï¼onupgradeneeded äºä»¶æè¢«è§¸ç¼ï¼ç¶å¾æåå¯ä»¥å¨ onupgradeneeded äºä»¶èçå¨ä¸åå»ºç«æ°ççæ¬ï¼ä¸é¢åç´è³æåº«çæ¬ææ´è©³ç´°ç說æã
ç¢çäºä»¶èçå¨å¹¾ä¹ææç¬¬ä¸ä»¶è¦å°è«æ±åçäºé½æ¯ç¢ç success å error äºä»¶èçå¨:
request.onerror = function (event) {
// Do something with request.errorCode!
};
request.onsuccess = function (event) {
// Do something with request.result!
};
妿ä¸åæ£å¸¸ï¼success äºä»¶(ä¹å°±æ¯ DOM äºä»¶ç type 屬æ§è¨çº success)æä»¥ request çºç®æ¨è§¸ç¼ï¼ç¶å¾ request ç©ä»¶ä¸ç onsuccess 彿¸æ¥è被å¼å«ï¼å ¶ä¸ success äºä»¶å°±æ¯åæ¸ï¼å¦å error äºä»¶(ä¹å°±æ¯ DOM äºä»¶ç type 屬æ§è¨çº error)æä»¥ request çºç®æ¨è§¸ç¼ï¼ç¶å¾ request ç©ä»¶ä¸ç onerror 彿¸æ¥è被å¼å«ï¼å ¶ä¸ error äºä»¶å°±æ¯åæ¸ã
IndexedDB ç API è¨è¨ä¸ç¡éæ¸å°é¯èª¤èçï¼æä»¥ä¸å¤ªå¸¸çå°é¯èª¤äºä»¶ï¼ä¸ééåè³æåº«çæå鿝æä¸äºçæ³æç¢ç¢çé¯èª¤ï¼æå¸¸è¦ççæ³æ¯ä½¿ç¨è æçµæå建ç«è³æåº«ã
IndexedDB è¨è¨ç®æ¨ä¹ä¸çºåæ¾å¤§éè³æä»¥ä¾é¢ç·ä½¿ç¨(è«åè"å²åéå¶"äºè§£æ´å¤ç´°ç¯)ãä½å¾æé¡¯å°ï¼ç覽å¨å䏿¨è¦ä¸äºå»£åç¶²ç«ææ¡æç¶²ç«æ±æé»è ¦ï¼æä»¥ç¶ä»»ä¸å網路æç¨ç¬¬ä¸æ¬¡éå IndexedDB è³æåº«ï¼çè¦½å¨æå¾µè©¢ä½¿ç¨è æ¯å¦åè¨±å ¶ä½æ¥ï¼åæå¨ç§å¯ç覽ä¸éå使¥ä¹æå¤±æï¼å çºç§å¯çè¦½ä¸æçä¸ä»»ä½ç覽çè·¡ã
é裡å¼å« indexedDB.open()éå indexedDB è³æåº«ä¸¦åå³ request ç©ä»¶ï¼åè¨ä½¿ç¨è å 許æåå»ºç« indexedDB è³æåº«ï¼æå乿¶å° suceess äºä»¶è§¸ç¼äº success åå¼å½æ¸(callback)ï¼request ç©ä»¶ç result å±¬æ§ææ¯ä¸å IDBDatabase ç©ä»¶ ï¼æ¥ä¸ä¾ä¾¿æ¯è¦å²åéåç©ä»¶ä¹å¾ä½¿ç¨ã䏿¹æ¯æ´å使¥ç示ç¯ç¨å¼ç¢¼:
var db;
var request = indexedDB.open("MyTestDatabase");
request.onerror = function (event) {
alert("Why didn't you allow my web app to use IndexedDB?!");
};
request.onsuccess = function (event) {
db = request.result;
};
é¯èª¤èç
é¯èª¤äºä»¶æåä¸å³éï¼é¯èª¤äºä»¶ä»¥ç¢çé¯èª¤ä¹è«æ±çºç®æ¨è§¸ç¼ï¼ç¶å¾ä¸è·¯å³éå°äº¤æï¼æå¾å°è³æåº«ç©ä»¶ï¼å¦æä¸æ³è¦çºæ¯ä¸åè«æ±æ°å¢é¯èª¤èçå¨ï¼å¯ä»¥æ¹çºè³æåº«ç©ä»¶å å ¥ä¸åé¯èª¤èçå¨ã
db.onerror = function (event) {
// Generic error handler for all errors targeted at this database's
// requests!
alert("Database error: " + event.target.errorCode);
};
æå¸¸è¦çé¯èª¤ä¹ä¸å°±æ¯ VER_ERRï¼è©²é¯èª¤ä»£è¡¨ç¾å¨è³ææåº«çæ¬å¤§æ¼å試éåçè³æåº«çæ¬ï¼éé é¯èª¤å¿ é è¦æé¯èª¤èçå¨èçã
å»ºç«ææ´æ°è³æåº«çæ¬æ°çæ¬è³æåº«å»ºç«æè§¸ç¼ onupgradeneeded äºä»¶ï¼å¨éåäºä»¶çèçå¨ä¸è¦å»ºç«éåçæ¬è³æåº«éè¦çç©ä»¶åæªã
// This event is only implemented in recent browsers
request.onupgradeneeded = function (event) {
var db = event.target.result;
// Create an objectStore for this database
var objectStore = db.createObjectStore("name", { keyPath: "myKey" });
};
è³æåº«çæ¬æ¯ unsigned long long çæ¸åï¼æä»¥è½å¤ é常é·ã
è¦åï¼ è«æ³¨æé乿å³èçæ¬ä¸è½çºæµ®é»æ¸ï¼å¦åå°æ¸é»é¨åå°æç¡æ¢ä»¶æ¨å»ï¼è交æä¹å¯è½ä¸æéå§ï¼upgradeneeded äºä»¶ä¹ä¸æè§¸ç¼ãä¸è¦å以ä¸ä¾å以 2.4 ä½çæ¬:
var request = indexedDB.open("MyTestDatabase", 2.4); // don't do this, as the version will be rounded to 2
åç´çæ¬è³æåº«å»ºç«æè§¸ç¼ onupgradeneeded äºä»¶ï¼éåæåè³æåº«è£¡é¢å·²ç¶å«æåçæ¬ä¸çç©ä»¶åæªï¼æä»¥èªªä¸éè¦å次建ç«éäºç©ä»¶åæªäºï¼å©ä¸çæ¯æ°å¢æåªé¤ç©ä»¶åæªã妿æ³è¦æ´åæ¢åç©ä»¶åæª(ä¾å¦æ¹è®è³æéµè·¯å¾)ï¼é£éº¼æéè¦å åªé¤èçåç¢çä¸åæ°ç(è«æ³¨æé乿åªé¤ç©ä»¶åæªè£¡çè³æï¼æä»¥å¦æè³æéè¦ä¿çç話ï¼è«å¨åç´åå è®åºè³æå份ã)
Webkit æ¯æ´ææ°æ¨æºä¸éåªæ Chrome 23 æéå§å°å ¥ï¼èè¼è䏿¯æ´ææ°çæ¨æºççæ¬å䏿¯æ´ indexedDB.open(name, version).onupgradeneededãéæ¼å¦ä½å¨èçæ¨æºä¸åç´è³æåº«çæ¬è«åè"IDBDatabase åèæç« "ã
çµæ§åè³æåº«indexedDB ä¸ç¨è³æè¡¨èæ¯ç©ä»¶åæªï¼ç©ä»¶åæªå¯ä»¥æå¾å¤ãä¸çç©ä»¶åæªè£¡çè³æå¼å°æä¸çè³æéµï¼ä¾æä½¿ç¨{è³æéµè·¯å¾(key path)}æ{è³æéµç¢çå¨(key generator)}ã
ä¸è¡¨ååºè³æå»ºåé¡ç¢çéå¾:
Key Path Key Generator æè¿° No No ç©ä»¶åæªè³æå¼è½çºä»»ä½åå¥ï¼å³ä½¿åæ¸åæåä¸²ãæ¯ç¶æ°å¢ä¸çè³æï¼å¿ é æä¾ä¸åçè³æéµã Yes No ç©ä»¶åæªè³æå¼å è½çº Javacript ç©ä»¶ï¼èè©²è³æç©ä»¶å¿ é 嫿åè³æéµè·¯å¾ç¸åå稱ä¹å±¬æ§æå¡ã No Yes ç©ä»¶åæªè³æå¼è½çºä»»ä½åå¥ï¼è³æéµèªåç¢çï¼ä½å¦ææ³è¦æå®è³æéµä¹å¯ä»¥å¦å¤æä¾è³æéµã Yes Yes ç©ä»¶åæªè³æå¼å è½çº Javascript ç©ä»¶ãé常被ç¢ççæ°è³æéµçå¼æè¢«åå¨ç©ä»¶å±¬æ§å稱åè³æéµè·¯å¾å稱ç¸åçç©ä»¶å±¬æ§ä¸ï¼å¦æéå屬æ§å·²ç¶åå¨ï¼éåå·²ç¶åå¨ä¹å±¬æ§ä¹å¼å°è¢«ç¨ä½çºè³æéµï¼èéæ°ç¢ççè³æéµãæåå¯ä»¥æ¿ä»»ä½å²åè³æçºç©ä»¶åæ èéåå§è³æåæ çç©ä»¶åæªå»ºç«ç´¢å¼ï¼ç´¢å¼è®æåè½å¤ ç¨ç©ä»¶åæªä¸è³æç©ä»¶å §çæä¸å屬æ§å¼æ¥æ¾è³æï¼èéå å ç©ä»¶çè³æéµã
餿¤ä¹å¤ï¼å©ç¨ç´¢å¼éå¯ä»¥æ½å ç°¡å®çå²åéå¶ï¼å»ºç«ç´¢å¼æè¨å®ç¨ç¹ææ¨(flag)ï¼éåç´¢å¼ä¿è卿¤ç´¢å¼è³æéµä¸ä¸æåå¨å ©åç©ä»¶åæªææåæ¨£è³æå¼ï¼æ¯å¦èªªç¾å¨æä¸ååæ¾è¨±å¤ä½¿ç¨è çç©ä»¶åæªï¼è䏿å叿ä¿è䏿åå¨æå ©å使ç¨è çé»åéµä»¶å°å䏿¨£ï¼æ¤ä½¿ç´¢å¼çç¨ç¹ææ¨ä¾¿å¯ä»¥å¹«å©æåéæç®æ¨ã
以ä¸è½èµ·ä¾å¯è½ææäºè¤éï¼è«çä¸ä¸ä¸é¢ç實ä¾:
// This is what our customer data looks like.
const customerData = [
{ ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },
{ ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" },
];
const dbName = "the_name";
var request = indexedDB.open(dbName, 2);
request.onerror = function (event) {
// Handle errors.
};
request.onupgradeneeded = function (event) {
var db = event.target.result;
// Create an objectStore to hold information about our customers. We're
// going to use "ssn" as our key path because it's guaranteed to be
// unique.
var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
// Create an index to search customers by name. We may have duplicates
// so we can't use a unique index.
objectStore.createIndex("name", "name", { unique: false });
// Create an index to search customers by email. We want to ensure that
// no two customers have the same email, so use a unique index.
objectStore.createIndex("email", "email", { unique: true });
// Store values in the newly created objectStore.
for (var i in customerData) {
objectStore.add(customerData[i]);
}
};
è«æ³¨æ onupgradeneeded äºä»¶æ¯å¯ä¸è½å¤ è®æ´è³æåº«çµæ§ä¹èï¼å¨æ¤äºä»¶æè½å»ºç«æåªé¤ç©ä»¶åæªä»¥å建ç«ååªé¤ç´¢å¼ã
å¼å«IDBDatabaseé¡å¥ç©ä»¶ç createObjectStore æ¹æ³æç«å»åµé ä¸åç©ä»¶åæªï¼éåæ¹æ³æ¥æ¶å ©å忏ï¼ä¸åæ¯ç©ä»¶åæªå稱ï¼ä¸åæ¯éå¿ å¡«ç忏ç©ä»¶ï¼éç¶åæ¸ç©ä»¶ä¸çºå¿ 填使¯å»ç¸ç¶éè¦ï¼å çºå®è®æåå®ç¾©äºä¸äºéè¦å±¬æ§(è«åècreateObjectStore)ãæ¬ä¾ä¸æåè¦æ±å»ºç«äºä¸å"customer"ç©ä»¶åæªï¼å®ç¾©"ssn"屬æ§çºè³æä»¶è·¯å¾ï¼ä½¿ç¨"ssn"ä½çºè³æéµè·¯å¾æ¯å çºæ¯å客æ¶ç ssn 碼ä¸å®æ¯ç¨ç«çã䏿¦æ±ºå®äº"ssn"ä½çºè³æéµè·¯å¾ï¼é£éº¼æ¯ä¸çè³æä¸å®è¦å«æ"ssn"ã
æ¬ä¾éåµå»ºä¸å稱çº"name"çç´¢å¼ï¼"name"ç´¢å¼æ¥æ¾ç®æ¨çºè³æç"name"屬æ§ï¼ä¸ä¸è¨ç«å ¶ç¨ç¹ææ¨(unique çº false)ï¼å樣å°ï¼æååå¼å«createIndexæ¹æ³åµå»ºäºä¸å"email"ç´¢å¼ï¼ä¸é"email"ç´¢å¼å ·åç¨ç¹ææ¨(unique çº true)ãéç¶åå¨"name"ç´¢å¼ï¼ä½è³æä¸ä¸å®è¦å«æ"name"屬æ§ï¼åªæ¯ç¶æç´¢"name"ç´¢å¼æè³æä¸æåºç¾ã
æ¥ä¸ä¾æåå¯ä»¥éå§ç¨ ssn å¾ç©ä»¶åæªä¸ååºè³æï¼ææ¯ç¨ç´¢å¼æ¾åºè³æï¼è«åè使ç¨ç´¢å¼ï¼ã
使ç¨è³æéµç¢çå¨ç¶å»ºç«ç©ä»¶åæªæè¨å® autoIncrement ææ¨çº ture å°ååè³æéµç¢çå¨ï¼é è¨ä¸è©²ææ¨çº falseã
æäºè³æéµç¢çå¨ï¼ç¶æ°å¢è³æå°ç©ä»¶åæªä¸ï¼è³æéµç¢ç卿èªå幫æåç¢çè³æéµãè³æéµç¢çå¨ç¢ççè³æéµç±æ´æ¸ 1 éå§ï¼èåºæ¬ä¸æ°ç¢ççè³æéµæ¯ç±åä¸åè³æéµå 1 ç¢çãè³æéµçç¢ç䏿å çºè³æåªé¤ææ¸ 空ææè³æèéæ°éå§èµ·ç®ï¼æä»¥è³æéµå¼æ¯ä¸ç´ç´¯å ä¸å»çï¼é¤éè³æåº«æä½ä¸æ·ï¼æ´å交æä½æ¥è¢«åæ¶ã
æåå¯ä»¥å»ºç«ä¸åæè³æéµç¢çå¨çç©ä»¶åæªå¦ä¸:
// Open the indexedDB.
var request = indexedDB.open(dbName, 3);
request.onupgradeneeded = function (event) {
var db = event.target.result;
// Create another object store called "names" with the autoIncrement flag set as true.
var objStore = db.createObjectStore("names", { autoIncrement: true });
// Because the "names" object store has the key generator, the key for the name value is generated automatically.
// The added records would be like:
// key : 1 => value : "Bill"
// key : 2 => value : "Donna"
for (var i in customerData) {
objStore.add(customerData[i].name);
}
};
éæ¼è³æéµç¢çå¨ç´°ç¯ï¼è«åè"W3C Key Generators"ã
æ°å¢ååªé¤è³æå¨æä½è³æåº«ä¹åå¿ é è¦å é²è¡äº¤æï¼äº¤æä¾èªè³æåº«ç©ä»¶ï¼å¨äº¤æä¸è¦æå®æ¶µèç©ä»¶åæªç¯åï¼ç¶å¾ä¹è¦æ±ºå®æ¯è¦è®æ´è³æåº«æç´ç²¹è®åè³æã交æå ±æä¸ç¨®ç¨®é¡ï¼å奿¯è®å(read-only)ï¼è®å¯«(read/write), 以åçæ¬è®æ´(versionchange)ï¼å¦æåªéè¦è®è³ææå¥½åªä½¿ç¨è®å(read-only)交æï¼å çºè®å(read-only)交æå¯ä»¥å¤é忥é²è¡ã
æ°å¢è³æå°è³æåº«åµå»ºè³æåº«å¾ï¼å¦æè¦å¯«å ¥è³æè«é麼å:
var transaction = db.transaction(["customers"], "readwrite");
// Note: Older experimental implementations use the deprecated constant IDBTransaction.READ_WRITE instead of "readwrite".
// In case you want to support such an implementation, you can just write:
// var transaction = db.transaction(["customers"], IDBTransaction.READ_WRITE);
å¼å«transaction()æ¹æ³æåå³ä¸å交æç©ä»¶ãtransaction()第ä¸åæ¥ååæ¸ä»£è¡¨äº¤ææ¶µèçç©ä»¶åæªï¼éç¶å³å ¥ç©ºé£åæè®äº¤ææ¶µèææç©ä»¶åæªï¼ä½è«ä¸è¦é麼åï¼å çºæ ¹ææ£å¼æ¨æºå³å ¥ç©ºé£åæè©²è¦å°è´ InvalidAccessError é¯èª¤ï¼ç¬¬äºååæ¸ä»£è¡¨äº¤æç¨®é¡ï¼ä¸å³å ¥ç話é è¨çºè®å交æï¼æ¬ä¾è¦å¯«å ¥è³æåº«æä»¥å³å ¥è®å¯«("readwrite")ã
交æççå½é±æåäºä»¶å¾ªç°éä¿å¯åãç¶æåç¼èµ·äº¤æååå°äºä»¶å¾ªç°ä¸å¾ï¼å¦æå¿½ç¥ï¼é£éº¼äº¤æå°è½æçµæï¼å¯ä¸ä¿æäº¤æåæ´»çæ¹æ³æ¯å¨äº¤æä¸ç¼åºè«æ±ï¼ç¶è«æ±å®æå¾æåææ¶å° DOM äºä»¶ï¼åè¨è«æ±çµææåï¼æåå¯ä»¥å¨äºä»¶çåå¼å½æ¸(callback ä¸)ç¹¼çºé²è¡äº¤æï¼åä¹ï¼å¦ææåæ²æç¹¼çºé²è¡äº¤æï¼é£éº¼äº¤æå°çµæï¼ä¹å°±æ¯èªªåªè¦å°ææªå®æè«æ±ç話ï¼äº¤æå°±æç¹¼çºåæ´»ï¼å¦ææ¶å° TRANSACTION_INACTIVE_ERR é¯èª¤é£ä¾¿æè¬èäº¤ææ©å·²çµæï¼æåé¯éäºç¹¼çºé²è¡äº¤æçæ©æã
交æè½æ¶å°ä¸ç¨®äºä»¶: é¯èª¤(error)ã䏿·(abort)以å宿(complete)ï¼å ¶ä¸é¯èª¤äºä»¶æåä¸å³éï¼æä»¥ä»»ä½ä¸å交æä¸è½çè«æ±ç¢çé¯èª¤äºä»¶ï¼è©²äº¤æé½ææ¶å°ãå¦æäº¤ææ¶å°é¯èª¤äºä»¶æï¼ç覽å¨é è¨è¡çºæä¸æ·äº¤æï¼é¤éæåæå¨é¯èª¤äºä»¶ä¸å¼å« preventDefault()黿ç覽å¨é è¨è¡åï¼å¦åæ´ç交æé½å°åæ¶ã復åï¼é樣çè¨è¨å訴æåå¿ é è¦æèå¦ä½è裡é¯èª¤ï¼æè èªªå¦æå°æ¯ä¸åé¯èª¤é²è¡èè£¡éæ¼éº»ç ©ï¼é£éº¼è³å°å å ¥ä¸åæ¦æ¬æ§çé¯èª¤èçå¨ä¹æ¯å¯ä»¥ãåªè¦ä¸è裡é¯èª¤æå¼å« abort()ï¼äº¤æå°åæ¶ã復åï¼ç¶å¾ä¸æ·äºä»¶æ¥è觸ç¼ï¼åä¹ï¼ç¶ææè«æ±é½å®æå¾ï¼æåææ¶å°ä¸å宿äºä»¶ï¼æä»¥èªªå¦ææååæç¼èµ·å¤é è«æ±æï¼å¯ä»¥åªè¿½è¹¤å®ä¸äº¤æèéåå¥è«æ±ï¼é樣æå¤§å¤§æ¸è¼æåçè² æã
æäºäº¤æä¹å¾ä¾¿è½å¤ å¾ä¸åå¾ç©ä»¶åæªï¼æäºç©ä»¶åæªä¾¿è½å¤ æ°å¢è³æ(è«æ³¨æå¯æå¨å»ºç«äº¤æææå®çç©ä»¶åæªè½å¤ åå¾)ã
// Do something when all the data is added to the database.
transaction.oncomplete = function (event) {
alert("All done!");
};
transaction.onerror = function (event) {
// Don't forget to handle errors!
};
var objectStore = transaction.objectStore("customers");
for (var i in customerData) {
var request = objectStore.add(customerData[i]);
request.onsuccess = function (event) {
// event.target.result == customerData[i].ssn;
};
}
å¼å«addæ¹æ³å¯ä»¥å å ¥ä¸çæ°è³æï¼å¼å«å¾æåå³ä¸åIDBRequestç©ä»¶ï¼å³çºä¸æ¹ç¯ä¾ä¸ç requestï¼å¦ææ°å¢æåï¼request çæåäºä»¶æè¢«è§¸ç¼ï¼èæåäºä»¶ç©ä»¶ä¸æä¸å result 屬æ§ï¼éå result å¼åå¥½å°±çæ¼æ°è³æçè³æéµï¼æä»¥èªªä¸æ¹ç¯ä¾ä¸ç event.target.result åå¥½å°±çæ¼é¡§å®¢ç ssn å¼(å çºæåç¨ ssn 屬æ§ä½çºè³æéµè·¯å¾)ãè«æ³¨æ add æ¹æ³åªå¨ç¶ç©ä»¶åæªä¸æ²æç¸åè³æéµè³æå卿æç¨ï¼å¦ææ³è¦æ´åææ¯ç´æ¥è¦èç¾åè³æè«å¼å«putæ¹æ³ã
ç§»é¤è³æç§»é¤è³æåå容æ:
var request = db
.transaction(["customers"], "readwrite")
.objectStore("customers")
.delete("444-44-4444");
request.onsuccess = function (event) {
// It's gone!
};
è®åè³æ
è¦ååè³æåº«å §çè³æææ¸ç¨®éå¾ï¼ç¬¬ä¸åæç°¡å®çéå¾å°±æ¯æä¾è³æéµï¼å¼å«getæ¹æ³åå¾è³æ:
var transaction = db.transaction(["customers"]);
var objectStore = transaction.objectStore("customers");
var request = objectStore.get("444-44-4444");
request.onerror = function (event) {
// Handle errors!
};
request.onsuccess = function (event) {
// Do something with the request.result!
alert("Name for SSN 444-44-4444 is " + request.result.name);
};
åè¨æåæé¯èª¤èçæ¾å¨è³æåº«å±¤ç´ï¼æåå¯ä»¥å縮çä¸é¢çç¨å¼ç¢¼å¦ä¸:
db
.transaction("customers")
.objectStore("customers")
.get("444-44-4444").onsuccess = function (event) {
alert("Name for SSN 444-44-4444 is " + event.target.result.name);
};
å¼å« transcation æ¹æ³è䏿宿¨¡å¼æéåè®å(readonly)模å¼ï¼æ¥èå徿åçç®æ¨ç©ä»¶åæªï¼è¼¸å ¥ç®æ¨è³æçè³æéµï¼å¼å« get æ¹æ³åå¾è«æ±ç©ä»¶ï¼ç¶å¾å¨è«æ±ç©ä»¶ä¸è¨»åæåäºä»¶èçå¨ï¼ç¶ä½æ¥æåå¾ï¼æåäºä»¶æè§¸ç¼ï¼æåäºä»¶çç©ä»¶ä¸å«æè«æ±ç©ä»¶(event.target å¦ä¸è¿°ç¯ä¾)ï¼è«æ±ç©ä»¶ä¸å«æè«æ±çµæ(event.target.result å¦ä¸è¿°ç¯ä¾)ã
ä½¿ç¨ææ¨(Cursor)ä½¿ç¨ get æ¹æ³éè¦ç¥éè³æéµï¼å¦ææ³è¦ä¸ä¸ååç©ä»¶åæªä¸çè³æï¼æåå¯ä»¥å©ç¨ææ¨:
var objectStore = db.transaction("customers").objectStore("customers");
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor.continue();
} else {
alert("No more entries!");
}
};
openCursoræ¹æ³ç¬¬ä¸å忏ç¨ä¾æ¥åè³æéµç¯åç©ä»¶ä¾éå¶ååè³æç¯åï¼ç¬¬äºå忏ç¨ä¾æå®ååé²è¡æ¹åï¼åä¸é¢çç¯ä¾ç¨å¼ä¾¿æ¯ä»¥è³æéµç±å°å°å¤§ä¹æ¹åååè³æï¼å¼å« openCursor æ¹æ³å¾ä¸æ¨£æåå³ä¸åè«æ±ç©ä»¶ï¼æåææåäºä»¶æè§¸ç¼ï¼ä¸éé裡æäºå°æ¹è¦ç¹å¥æ³¨æï¼ç¶æåäºä»¶èè£¡å½æ¸è¢«åèµ·æï¼ææ¨ç©ä»¶(cursor)æåæ¾å¨ result 屬æ§å §(亦å³ä¸è¿° event.target.result)ï¼cursor ç©ä»¶ä¸æå ©å屬æ§ï¼key å±¬æ§æ¯è³æéµï¼value å±¬æ§æ¯è³æå¼ï¼å¦æè¦åå¾ä¸ä¸ä»½è³æå°±å¼å« cursor ç continue()æ¹æ³ï¼ç¶å¾ cursor ç©ä»¶å°±ææåä¸ä¸ä»½è³æï¼ç¶æ²æè³ææï¼cursor ææ¯ undefinedï¼ç¶è«æ±ä¸éå§ä¾¿æ¾æ²æè³æï¼result 屬æ§ä¹ææ¯ undefinedã
以ä¸ç¨ cursor ååä¸éè³æå¾æ¾å¨é£åä¸ç使³ç¸ç¶å¸¸è¦:
var customers = [];
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
customers.push(cursor.value);
cursor.continue();
} else {
alert("Got all customers: " + customers);
}
};
è¦åï¼ ä»¥ä¸ç¯ä¾ä¸æ¯ IndexedDB æ¨æº!
Mozilla ç覽å¨èªå·±åäºä¸å getAll()æ¹æ³ä¾æ¹ä¾¿ä¸æ¬¡å徿æ cursor ä¸çè³æå¼ï¼éåæ¹æ³ç¸ç¶æ¹ä¾¿ï¼ä¸éè«å°å¿æªä¾å®æå¯è½ææ¶å¤±ã以ä¸ç¨å¼ç¢¼çææåä¸é¢ç䏿¨£:
objectStore.getAll().onsuccess = function (event) {
alert("Got all customers: " + event.target.result);
};
ä¸ä¸æª¢æ¥ cursor ç value 屬æ§è¼ä¸å©æ§è½è¡¨ç¾ï¼å çºç©ä»¶æ¯è¢«åä¸ä¸å»ºç«ï¼ç¶èå¼å« getAll()ï¼Gecko ä¸å®è¦ä¸æ¬¡å»ºç«ææç©ä»¶ï¼æä»¥å¦ææ³è¦ä¸æ¬¡å徿æç©ä»¶çè³æå¼é£åä½¿ç¨ getAll()æ¯è¼å¥½ï¼å¦ææ³è¦ä¸ä¸æª¢æ¥æ¯çè³æåè«å©ç¨ cursor çæ¹æ³ã
使ç¨ç´¢å¼å©ç¨ä¸å®å¯ä¸ç ssn 碼ä½çºè³æéµç¸ç¶åä¹é輯(é±ç§æ¬çåé¡å æ±ç½®ä¸æ¾ï¼ä¸å¨æ¬ææ¢è¨ç¯å)ãä¸éç¶æåæ³è¦æ¥è©¢ä½¿ç¨è çååçæåï¼å¦ææ²æç´¢å¼å°±éè¦ä¸ä¸æª¢æ¥æ¯ä¸çè³æï¼ååæ²ææçï¼æä»¥æåå¯ä»¥å»ºç« name çç´¢å¼ã
var index = objectStore.index("name");
index.get("Donna").onsuccess = function (event) {
alert("Donna's SSN is " + event.target.result.ssn);
};
å çº name 䏿¯å¯ä¸å¼ï¼æä»¥å¯è½ææå¤çè³æç¬¦å"Donna"ååï¼æ¤æå¼å« get()æåå¾è³æéµæå°å¼çè³æã
妿æåæ³è¦æ¥çç¹å®åå䏿æçè³æï¼å¯ä»¥å©ç¨ cursorãæå ©ç¨® cursor è½ç¨å¨ç´¢å¼ä¸ï¼ç¬¬ä¸ç¨®ä¸è¬ cursor ææ¯å°ç´¢å¼å¼ä¸¦å峿´ä»½è³æ(ç©ä»¶åæªä¸çç©ä»¶)ï¼ç¬¬äºç¨®è³æéµ cursor ååªæåå³è³æéµå¼ï¼è«åè䏿¹ç¯ä¾æ¯è¼å ©è å·®ç°:
index.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
// cursor.key is a name, like "Bill", and cursor.value is the whole object.
alert(
"Name: " +
cursor.key +
", SSN: " +
cursor.value.ssn +
", email: " +
cursor.value.email,
);
cursor.continue();
}
};
index.openKeyCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
// cursor.key is a name, like "Bill", and cursor.value is the SSN.
// No way to directly get the rest of the stored object.
alert("Name: " + cursor.key + ", SSN: " + cursor.value);
cursor.continue();
}
};
è¨å®ææ¨æ¥è©¢ç¯ååæ¹å
妿æ³è¦éå®ææ¨æ¥è©¢ç¯åï¼é£éº¼å¨ä¹å« openCursor()æ openKeyCursor()æç¬¬ä¸å忏è¦å³å ¥IDBKeyRangeç©ä»¶ä»¥éå¶ç¯åãIDBKeyRange ç©ä»¶è½å¤ åªèç¦å¨å®ä¸è³æéµä¸æè 䏿®µä¸ä¸éåéï¼ä¸ä¸éåéå¯ä»¥æ¯å°é(å«çé)æéæ¾(ä¸å«çé)ï¼è«ç以ä¸ç¯ä¾:
// Only match "Donna"
var singleKeyRange = IDBKeyRange.only("Donna");
// Match anything past "Bill", including "Bill"
var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");
// Match anything past "Bill", but don't include "Bill"
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);
// Match anything up to, but not including, "Donna"
var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);
// Match anything between "Bill" and "Donna", but not including "Donna"
var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);
index.openCursor(boundKeyRange).onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
// Do something with the matches.
cursor.continue();
}
};
ææåæåææ³è¦ç±å¤§å°å°æ¥çè³æèéé è¨ç±å°å°å¤§æ¹åï¼å³å ¥ç¬¬äºå"prev"å串便è½åå°:
objectStore.openCursor(null, "prev").onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
// Do something with the entries.
cursor.continue();
}
};
ç±æ¼"name"ç´¢å¼ä¸å ·å¯ä¸æ§ï¼æä»¥ä¸åååä¸å¯è½æåºç¾å¤çè³æï¼æ¤æå¦ææ³è¦é¿ééå¤çè³æï¼è«å³å ¥"nextunique"æ"prevunique"åçºç¬¬äºåæ¹å忏ï¼ç¶å³å ¥ä¹å¾ï¼å¦ä¸åååä¸éå°å¤çè³æï¼ååªæè³æéµæå°çè³ææè¢«åå³ã
index.openKeyCursor(null, "nextunique").onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
// Do something with the entries.
cursor.continue();
}
};
éæ¼å¯å³å ¥çæ¹å忏ï¼è«åèIDBCursor常æ¸ã
ç¶ç¶²é æç¨ç¨å¼æ¼ç覽å¨å¦ä¸ååé éåæè®æ´çæ¬è«æè以ä¸çæ³: 使ç¨è å¨ç¬¬ä¸åç覽å¨åé ä¸ä½¿ç¨èèçæ¬ï¼ç¶å¾ä½¿ç¨è åæé第äºååé è¼å ¥ç¶²é ï¼æ¤ææå卿°åé éè¦å°è³æåº«é²è¡åç´ï¼æä»¥å¼å« open()ä»¥æ´æ°çæ¬éåè³æåº«ï¼ä½æ¯ç±æ¼ç¬¬ä¸åç覽å¨åé ä¸¦æ²æééè³æåº«ï¼å æ¤ç¬¬äºååé çè³æåº«åç´ä½æ¥æè¢«æä½ãæä»¥æåéè¦æ³¨æå¤ååé åæéåççæ³ï¼æ¯ååé é½å¾æ³¨æç¶ç¼çè³æåº«åç´äºä»¶æï¼è¦è¨å¾ééè³æåº«ï¼è®è³æåº«åç´ä½æ¥å¾ä»¥é²è¡ã實é使³å¦ä¸:
var openReq = mozIndexedDB.open("MyTestDatabase", 2);
openReq.onblocked = function (event) {
// If some other tab is loaded with the database, then it needs to be closed
// before we can proceed.
alert("Please close all other tabs with this site open!");
};
openReq.onupgradeneeded = function (event) {
// All other databases have been closed. Set everything up.
db.createObjectStore(/* ... */);
useDatabase(db);
};
openReq.onsuccess = function (event) {
var db = event.target.result;
useDatabase(db);
return;
};
function useDatabase(db) {
// Make sure to add a handler to be notified if another page requests a version
// change. We must close the database. This allows the other page to upgrade the database.
// If you don't do this then the upgrade won't happen until the user closes the tab.
db.onversionchange = function (event) {
db.close();
alert("A new version of this page is ready. Please reload!");
};
// Do stuff with the database.
}
å®å
¨æ§
IndexedDB éµå®åæºæ¿çï¼æä»¥å®ç¶å®åµå»ºå®ç便ºç¶²ç«ï¼å
¶ä»ä¾æºç¶²ç«ç¡æ³ååãå°±åå°è¼å
¥ <frame>
å <iframe>
ç¶²é çç¬¬ä¸æ¹ cookie æè¨ä¸çå®å
¨æ§åé±ç§æ¬èééå¶ï¼IndexedDB ç¡æ³å¨è¼å
¥ <frame>
å <iframe>
ç¶²é ä¸éä½ï¼è©³æ
è«è¦ Firefox bug 595307ã
ç¶ç覽å¨ééï¼ä¾å¦ä½¿ç¨è æä¸éééï¼ä»»ä½æªå®æ IndexedDB 交æé½å°é»é»ä¸æ¢ï¼éäºäº¤æä¸æå®æï¼é¯èª¤äºä»¶ä¹ä¸æè§¸ç¼ãæ¢ç¶ç覽å¨å¯è½é¨æè¢«ééï¼æåç¡æ³å®å ¨ææä»»ä½ç¹å®äº¤æä¸å®æå®æï¼ææ¯ä¾è³´é¯èª¤äºä»¶ååºç¸æèçï¼éå°éç¨®çæ³ï¼æåéè¦æ³¨æ:
第ä¸ãæ¯ä¸ç交æçµæå¾é½æè©²è¦ä¿æè³æåº«å®æ´æ§ï¼ä¾å¦èªªï¼æä¸ä¸²ä½¿ç¨è 編輯é ç®æ¸ 宿£è¦åå ¥è³æåº«ï¼æå妿å å¨ä¸å交æä¸æ¸ é¤èæ¸ å®ï¼ç¶å¾å¨å¦ä¸å交æä¸åå ¥æ°æ¸ å®ï¼é£å°±æé¢è¨å°æ¸ é¤å®å°±æ¸ å®å¾ï¼æ°æ¸ å®åå ¥äº¤æéä¾ä¸åååï¼ç覽å¨å°±ééç風éªï¼èéåæåè³æåº«è£¡é¢çæ¸ å®è³æå°æ¶å¤±ãæä»¥æ¯è¼å¥½çåæ³æè©²æ¯å¨åä¸ç交æä¸å®ææ¸ é¤èæ¸ å®ååå ¥æ°æ¸ å®ã
第äºãæ°¸é ä¸è¦å¨ unload äºä»¶ä¸å·è¡è³æåº«äº¤æï¼å çºå¦æ unload äºä»¶æ¯è§¸ç¼å¨ç覽å¨ééä¸ï¼ä»»ä½è³æåº«äº¤æé½ä¸æç¼çï¼æè¨±ï¼ç覽å¨(æåé )æéæè®åè³æåº«ï¼æ´æ°è³æåº«ç¶ä½¿ç¨è ç·¨è¼¯è³æï¼ç¶ç覽å¨(æåé )ééæå²åè³æéæ¨£çåæ³æ¯è¼ç´è¦ºï¼ä¸éè³æåº«çæä½æ¯é忥é²è¡å°ï¼æä»¥ç覽å¨ééçå·è¡æå¨è³æåº«æä½åç¼çï¼é²è䏿·å¾çºé忥çè³æåº«äº¤æï¼æä»¥å¨ unload äºä»¶ä¸å·è¡è³æåº«äº¤ææ¯è¡ä¸éå°ã
äºå¯¦ä¸ä¸è«çè¦½å¨æ¯å¦æ£å¸¸ééï¼é½æ²æä»»ä½æ¹æ³ä¿è IndexedDB 交æè½å¤ é å©å®æï¼è«è¦ Firefox bug 870645ã
宿´ IndexedDB ç¯ä¾ HTML<script
type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<h1>IndexedDB Demo: storing blobs, e-publication example</h1>
<div class="note">
<p>Works and tested with:</p>
<div id="compat"></div>
</div>
<div id="msg"></div>
<form id="register-form">
<table>
<tbody>
<tr>
<td>
<label for="pub-title" class="required"> Title: </label>
</td>
<td>
<input type="text" id="pub-title" name="pub-title" />
</td>
</tr>
<tr>
<td>
<label for="pub-biblioid" class="required">
Bibliographic ID:<br />
<span class="note">(ISBN, ISSN, etc.)</span>
</label>
</td>
<td>
<input type="text" id="pub-biblioid" name="pub-biblioid" />
</td>
</tr>
<tr>
<td>
<label for="pub-year"> Year: </label>
</td>
<td>
<input type="number" id="pub-year" name="pub-year" />
</td>
</tr>
</tbody>
<tbody>
<tr>
<td>
<label for="pub-file"> File image: </label>
</td>
<td>
<input type="file" id="pub-file" />
</td>
</tr>
<tr>
<td>
<label for="pub-file-url">
Online-file image URL:<br />
<span class="note">(same origin URL)</span>
</label>
</td>
<td>
<input type="text" id="pub-file-url" name="pub-file-url" />
</td>
</tr>
</tbody>
</table>
<div class="button-pane">
<input type="button" id="add-button" value="Add Publication" />
<input type="reset" id="register-form-reset" />
</div>
</form>
<form id="delete-form">
<table>
<tbody>
<tr>
<td>
<label for="pub-biblioid-to-delete">
Bibliographic ID:<br />
<span class="note">(ISBN, ISSN, etc.)</span>
</label>
</td>
<td>
<input
type="text"
id="pub-biblioid-to-delete"
name="pub-biblioid-to-delete" />
</td>
</tr>
<tr>
<td>
<label for="key-to-delete">
Key:<br />
<span class="note">(for example 1, 2, 3, etc.)</span>
</label>
</td>
<td>
<input type="text" id="key-to-delete" name="key-to-delete" />
</td>
</tr>
</tbody>
</table>
<div class="button-pane">
<input type="button" id="delete-button" value="Delete Publication" />
<input
type="button"
id="clear-store-button"
value="Clear the whole store"
class="destructive" />
</div>
</form>
<form id="search-form">
<div class="button-pane">
<input
type="button"
id="search-list-button"
value="List database content" />
</div>
</form>
<div>
<div id="pub-msg"></div>
<div id="pub-viewer"></div>
<ul id="pub-list"></ul>
</div>
CSS
body {
font-size: 0.8em;
font-family: Sans-Serif;
}
form {
background-color: #cccccc;
border-radius: 0.3em;
display: inline-block;
margin-bottom: 0.5em;
padding: 1em;
}
table {
border-collapse: collapse;
}
input {
padding: 0.3em;
border-color: #cccccc;
border-radius: 0.3em;
}
.required:after {
content: "*";
color: red;
}
.button-pane {
margin-top: 1em;
}
#pub-viewer {
float: right;
width: 48%;
height: 20em;
border: solid #d092ff 0.1em;
}
#pub-viewer iframe {
width: 100%;
height: 100%;
}
#pub-list {
width: 46%;
background-color: #eeeeee;
border-radius: 0.3em;
}
#pub-list li {
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-right: 0.5em;
}
#msg {
margin-bottom: 1em;
}
.action-success {
padding: 0.5em;
color: #00d21e;
background-color: #eeeeee;
border-radius: 0.2em;
}
.action-failure {
padding: 0.5em;
color: #ff1408;
background-color: #eeeeee;
border-radius: 0.2em;
}
.note {
font-size: smaller;
}
.destructive {
background-color: orange;
}
.destructive:hover {
background-color: #ff8000;
}
.destructive:active {
background-color: red;
}
JavaScript
(function () {
var COMPAT_ENVS = [
["Firefox", ">= 16.0"],
[
"Google Chrome",
">= 24.0 (you may need to get Google Chrome Canary), NO Blob storage support",
],
];
var compat = $("#compat");
compat.empty();
compat.append('<ul id="compat-list"></ul>');
COMPAT_ENVS.forEach(function (val, idx, array) {
$("#compat-list").append("<li>" + val[0] + ": " + val[1] + "</li>");
});
const DB_NAME = "mdn-demo-indexeddb-epublications";
const DB_VERSION = 1; // Use a long long for this value (don't use a float)
const DB_STORE_NAME = "publications";
var db;
// Used to keep track of which view is displayed to avoid uselessly reloading it
var current_view_pub_key;
function openDb() {
console.log("openDb ...");
var req = indexedDB.open(DB_NAME, DB_VERSION);
req.onsuccess = function (evt) {
// Better use "this" than "req" to get the result to avoid problems with
// garbage collection.
// db = req.result;
db = this.result;
console.log("openDb DONE");
};
req.onerror = function (evt) {
console.error("openDb:", evt.target.errorCode);
};
req.onupgradeneeded = function (evt) {
console.log("openDb.onupgradeneeded");
var store = evt.currentTarget.result.createObjectStore(DB_STORE_NAME, {
keyPath: "id",
autoIncrement: true,
});
store.createIndex("biblioid", "biblioid", { unique: true });
store.createIndex("title", "title", { unique: false });
store.createIndex("year", "year", { unique: false });
};
}
/**
* @param {string} store_name
* @param {string} mode either "readonly" or "readwrite"
*/
function getObjectStore(store_name, mode) {
var tx = db.transaction(store_name, mode);
return tx.objectStore(store_name);
}
function clearObjectStore(store_name) {
var store = getObjectStore(DB_STORE_NAME, "readwrite");
var req = store.clear();
req.onsuccess = function (evt) {
displayActionSuccess("Store cleared");
displayPubList(store);
};
req.onerror = function (evt) {
console.error("clearObjectStore:", evt.target.errorCode);
displayActionFailure(this.error);
};
}
function getBlob(key, store, success_callback) {
var req = store.get(key);
req.onsuccess = function (evt) {
var value = evt.target.result;
if (value) success_callback(value.blob);
};
}
/**
* @param {IDBObjectStore=} store
*/
function displayPubList(store) {
console.log("displayPubList");
if (typeof store == "undefined")
store = getObjectStore(DB_STORE_NAME, "readonly");
var pub_msg = $("#pub-msg");
pub_msg.empty();
var pub_list = $("#pub-list");
pub_list.empty();
// Resetting the iframe so that it doesn't display previous content
newViewerFrame();
var req;
req = store.count();
// Requests are executed in the order in which they were made against the
// transaction, and their results are returned in the same order.
// Thus the count text below will be displayed before the actual pub list
// (not that it is algorithmically important in this case).
req.onsuccess = function (evt) {
pub_msg.append(
"<p>There are <strong>" +
evt.target.result +
"</strong> record(s) in the object store.</p>",
);
};
req.onerror = function (evt) {
console.error("add error", this.error);
displayActionFailure(this.error);
};
var i = 0;
req = store.openCursor();
req.onsuccess = function (evt) {
var cursor = evt.target.result;
// If the cursor is pointing at something, ask for the data
if (cursor) {
console.log("displayPubList cursor:", cursor);
req = store.get(cursor.key);
req.onsuccess = function (evt) {
var value = evt.target.result;
var list_item = $(
"<li>" +
"[" +
cursor.key +
"] " +
"(biblioid: " +
value.biblioid +
") " +
value.title +
"</li>",
);
if (value.year != null) list_item.append(" - " + value.year);
if (
value.hasOwnProperty("blob") &&
typeof value.blob != "undefined"
) {
var link = $('<a href="' + cursor.key + '">File</a>');
link.on("click", function () {
return false;
});
link.on("mouseenter", function (evt) {
setInViewer(evt.target.getAttribute("href"));
});
list_item.append(" / ");
list_item.append(link);
} else {
list_item.append(" / No attached file");
}
pub_list.append(list_item);
};
// Move on to the next object in store
cursor.continue();
// This counter serves only to create distinct ids
i++;
} else {
console.log("No more entries");
}
};
}
function newViewerFrame() {
var viewer = $("#pub-viewer");
viewer.empty();
var iframe = $("<iframe />");
viewer.append(iframe);
return iframe;
}
function setInViewer(key) {
console.log("setInViewer:", arguments);
key = Number(key);
if (key == current_view_pub_key) return;
current_view_pub_key = key;
var store = getObjectStore(DB_STORE_NAME, "readonly");
getBlob(key, store, function (blob) {
console.log("setInViewer blob:", blob);
var iframe = newViewerFrame();
// It is not possible to set a direct link to the
// blob to provide a mean to directly download it.
if (blob.type == "text/html") {
var reader = new FileReader();
reader.onload = function (evt) {
var html = evt.target.result;
iframe.load(function () {
$(this).contents().find("html").html(html);
});
};
reader.readAsText(blob);
} else if (blob.type.indexOf("image/") == 0) {
iframe.load(function () {
var img_id = "image-" + key;
var img = $('<img id="' + img_id + '"/>');
$(this).contents().find("body").html(img);
var obj_url = window.URL.createObjectURL(blob);
$(this)
.contents()
.find("#" + img_id)
.attr("src", obj_url);
window.URL.revokeObjectURL(obj_url);
});
} else if (blob.type == "application/pdf") {
$("*").css("cursor", "wait");
var obj_url = window.URL.createObjectURL(blob);
iframe.load(function () {
$("*").css("cursor", "auto");
});
iframe.attr("src", obj_url);
window.URL.revokeObjectURL(obj_url);
} else {
iframe.load(function () {
$(this).contents().find("body").html("No view available");
});
}
});
}
/**
* @param {string} biblioid
* @param {string} title
* @param {number} year
* @param {string} url the URL of the image to download and store in the local
* IndexedDB database. The resource behind this URL is subjected to the
* "Same origin policy", thus for this method to work, the URL must come from
* the same origin as the web site/app this code is deployed on.
*/
function addPublicationFromUrl(biblioid, title, year, url) {
console.log("addPublicationFromUrl:", arguments);
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
// Setting the wanted responseType to "blob"
// http://www.w3.org/TR/XMLHttpRequest2/#the-response-attribute
xhr.responseType = "blob";
xhr.onload = function (evt) {
if (xhr.status == 200) {
console.log("Blob retrieved");
var blob = xhr.response;
console.log("Blob:", blob);
addPublication(biblioid, title, year, blob);
} else {
console.error(
"addPublicationFromUrl error:",
xhr.responseText,
xhr.status,
);
}
};
xhr.send();
// We can't use jQuery here because as of jQuery 1.8.3 the new "blob"
// responseType is not handled.
// http://bugs.jquery.com/ticket/11461
// http://bugs.jquery.com/ticket/7248
// $.ajax({
// url: url,
// type: 'GET',
// xhrFields: { responseType: 'blob' },
// success: function(data, textStatus, jqXHR) {
// console.log("Blob retrieved");
// console.log("Blob:", data);
// // addPublication(biblioid, title, year, data);
// },
// error: function(jqXHR, textStatus, errorThrown) {
// console.error(errorThrown);
// displayActionFailure("Error during blob retrieval");
// }
// });
}
/**
* @param {string} biblioid
* @param {string} title
* @param {number} year
* @param {Blob=} blob
*/
function addPublication(biblioid, title, year, blob) {
console.log("addPublication arguments:", arguments);
var obj = { biblioid: biblioid, title: title, year: year };
if (typeof blob != "undefined") obj.blob = blob;
var store = getObjectStore(DB_STORE_NAME, "readwrite");
var req;
try {
req = store.add(obj);
} catch (e) {
if (e.name == "DataCloneError")
displayActionFailure(
"This engine doesn't know how to clone a Blob, " + "use Firefox",
);
throw e;
}
req.onsuccess = function (evt) {
console.log("Insertion in DB successful");
displayActionSuccess();
displayPubList(store);
};
req.onerror = function () {
console.error("addPublication error", this.error);
displayActionFailure(this.error);
};
}
/**
* @param {string} biblioid
*/
function deletePublicationFromBib(biblioid) {
console.log("deletePublication:", arguments);
var store = getObjectStore(DB_STORE_NAME, "readwrite");
var req = store.index("biblioid");
req.get(biblioid).onsuccess = function (evt) {
if (typeof evt.target.result == "undefined") {
displayActionFailure("No matching record found");
return;
}
deletePublication(evt.target.result.id, store);
};
req.onerror = function (evt) {
console.error("deletePublicationFromBib:", evt.target.errorCode);
};
}
/**
* @param {number} key
* @param {IDBObjectStore=} store
*/
function deletePublication(key, store) {
console.log("deletePublication:", arguments);
if (typeof store == "undefined")
store = getObjectStore(DB_STORE_NAME, "readwrite");
// As per spec https://www.w3.org/TR/IndexedDB/#object-store-deletion-operation
// the result of the Object Store Deletion Operation algorithm is
// undefined, so it's not possible to know if some records were actually
// deleted by looking at the request result.
var req = store.get(key);
req.onsuccess = function (evt) {
var record = evt.target.result;
console.log("record:", record);
if (typeof record == "undefined") {
displayActionFailure("No matching record found");
return;
}
// Warning: The exact same key used for creation needs to be passed for
// the deletion. If the key was a Number for creation, then it needs to
// be a Number for deletion.
req = store.delete(key);
req.onsuccess = function (evt) {
console.log("evt:", evt);
console.log("evt.target:", evt.target);
console.log("evt.target.result:", evt.target.result);
console.log("delete successful");
displayActionSuccess("Deletion successful");
displayPubList(store);
};
req.onerror = function (evt) {
console.error("deletePublication:", evt.target.errorCode);
};
};
req.onerror = function (evt) {
console.error("deletePublication:", evt.target.errorCode);
};
}
function displayActionSuccess(msg) {
msg = typeof msg != "undefined" ? "Success: " + msg : "Success";
$("#msg").html('<span class="action-success">' + msg + "</span>");
}
function displayActionFailure(msg) {
msg = typeof msg != "undefined" ? "Failure: " + msg : "Failure";
$("#msg").html('<span class="action-failure">' + msg + "</span>");
}
function resetActionStatus() {
console.log("resetActionStatus ...");
$("#msg").empty();
console.log("resetActionStatus DONE");
}
function addEventListeners() {
console.log("addEventListeners");
$("#register-form-reset").click(function (evt) {
resetActionStatus();
});
$("#add-button").click(function (evt) {
console.log("add ...");
var title = $("#pub-title").val();
var biblioid = $("#pub-biblioid").val();
if (!title || !biblioid) {
displayActionFailure("Required field(s) missing");
return;
}
var year = $("#pub-year").val();
if (year != "") {
// Better use Number.isInteger if the engine has EcmaScript 6
if (isNaN(year)) {
displayActionFailure("Invalid year");
return;
}
year = Number(year);
} else {
year = null;
}
var file_input = $("#pub-file");
var selected_file = file_input.get(0).files[0];
console.log("selected_file:", selected_file);
// Keeping a reference on how to reset the file input in the UI once we
// have its value, but instead of doing that we rather use a "reset" type
// input in the HTML form.
//file_input.val(null);
var file_url = $("#pub-file-url").val();
if (selected_file) {
addPublication(biblioid, title, year, selected_file);
} else if (file_url) {
addPublicationFromUrl(biblioid, title, year, file_url);
} else {
addPublication(biblioid, title, year);
}
});
$("#delete-button").click(function (evt) {
console.log("delete ...");
var biblioid = $("#pub-biblioid-to-delete").val();
var key = $("#key-to-delete").val();
if (biblioid != "") {
deletePublicationFromBib(biblioid);
} else if (key != "") {
// Better use Number.isInteger if the engine has EcmaScript 6
if (key == "" || isNaN(key)) {
displayActionFailure("Invalid key");
return;
}
key = Number(key);
deletePublication(key);
}
});
$("#clear-store-button").click(function (evt) {
clearObjectStore();
});
var search_button = $("#search-list-button");
search_button.click(function (evt) {
displayPubList();
});
}
openDb();
addEventListeners();
})(); // Immediately-Invoked Function Expression (IIFE)
ç·ä¸ç¯ä¾ ä¸ä¸æ¥
è«åèIndexedDB æä»¶ï¼ççæç麼 IndexedDB API å¯ä¾ä½¿ç¨ï¼å¯¦é試ç©ä¸ä¸å§ã
延伸é±è®RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4