您的位置:新葡亰496net > 新葡亰官网 > 基本使用,Web应用中的离线数据存储

基本使用,Web应用中的离线数据存储

发布时间:2019-06-16 08:35编辑:新葡亰官网浏览(101)

    indexedDB 基本使用

    2017/12/14 · 基础技术 · 1 评论 · IndexedDB

    原文出处: 党黎明   


    indexedDB简介:

    indexedDB 是一种使用浏览器存储大量数据的方法.它创造的数据可以被查询,并且可以离线使用.

     

    indexedDB 有以下特点:

    1. indexedDBWebSQL 数据库的取代品
    2. indexedDB遵循同源协议(只能访问同域中存储的数据,而不能访问其他域的)
    3. API包含异步API同步API两种:多数情况下使用异步API; 同步API必须同 WebWorkers 一起使用, 目前没有浏览器支持同步API
    4. indexedDB 是事务模式的数据库, 使用 key-value 键值对储存数据
    5. indexedDB 不使用结构化查询语言(SQL). 它通过索引(index)所产生的指针(cursor)来完成查询操作

    介绍

    IndexedDB就是一个数据库
    其最大的特点是: 使用对象保存数据,而不是使用表来保存数据,同时,它是异步的

    深入解析HTML5中的IndexedDB索引数据库,html5indexeddb

    这篇文章主要介绍了深入解析HTML5中的IndexedDB索引数据库,包括事务锁等基本功能的相关使用示例,需要的朋友可以参考下

    介绍 IndexedDB是HTML5 WEB数据库,允许HTML5 WEB应用在用户浏览器端存储数据。对于应用来说IndexedDB非常强大、有用,可以在客户端的chrome,IE,Firefox等WEB浏览器中存储大量数据,下面简单介绍一下IndexedDB的基本概念。
     
    什么是IndexedDB IndexedDB,HTML5新的数据存储,可以在客户端存储、操作数据,可以使应用加载地更快,更好地响应。它不同于关系型数据库,拥有数据表、记录。它影响着我们设计和创建应用程序的方式。IndexedDB 创建有数据类型和简单的JavaScript持久对象的object,每个object可以有索引,使其有效地查询和遍历整个集合。本文为您提供了如何在Web应用程序中使用IndexedDB的真实例子。
     
    开始 我们需要在执行前包含下面前置代码

    JavaScript Code复制内容到剪贴板

    1. var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;   
    2.     
    3. //prefixes of window.IDB objects   
    4. var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;   
    5. var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange   
    6.     
    7. if (!indexedDB) {   
    8. alert("Your browser doesn't support a stable version of IndexedDB.")   
    9. }  

     
    打开IndexedDB 在创建数据库之前,我们首先需要为数据库创建数据,假设我们有如下的用户信息:

    JavaScript Code复制内容到剪贴板

    1. var userData = [   
    2. { id: "1", name: "Tapas", age: 33, email: "[email protected]" },   
    3. { id: "2", name: "Bidulata", age: 55, email: "[email protected]" }   
    4. ];  

    现在我们需要用open()方法打开我们的数据库:

    JavaScript Code复制内容到剪贴板

    1. var db;   
    2. var request = indexedDB.open("databaseName", 1);   
    3.     
    4. request.onerror = function(e) {   
    5. console.log("error: ", e);   
    6. };   
    7.     
    8. request.onsuccess = function(e) {   
    9. db = request.result;   
    10. console.log("success: "  db);   
    11. };   
    12. request.onupgradeneeded = function(e) {   
    13.     
    14. }  

    如上所示,我们已经打开了名为"databaseName",指定版本号的数据库,open()方法有两个参数:
    1.第一个参数是数据库名称,它会检测名称为"databaseName"的数据库是否已经存在,如果存在则打开它,否则创建新的数据库。
    2.第二个参数是数据库的版本,用于用户更新数据库结构。
     
    onSuccess处理 发生成功事件时“onSuccess”被触发,如果所有成功的请求都在此处理,我们可以通过赋值给db变量保存请求的结果供以后使用。
     
    onerror的处理程序 发生错误事件时“onerror”被触发,如果打开数据库的过程中失败。
     
    Onupgradeneeded处理程序 如果你想更新数据库(创建,删除或修改数据库),那么你必须实现onupgradeneeded处理程序,使您可以在数据库中做任何更改。 在“onupgradeneeded”处理程序中是可以改变数据库的结构的唯一地方。
     
    创建和添加数据到表:
    IndexedDB使用对象存储来存储数据,而不是通过表。 每当一个值存储在对象存储中,它与一个键相关联。 它允许我们创建的任何对象存储索引。 索引允许我们访问存储在对象存储中的值。 下面的代码显示了如何创建对象存储并插入预先准备好的数据:

    JavaScript Code复制内容到剪贴板

    1. request.onupgradeneeded = function(event) {   
    2. var objectStore = event.target.result.createObjectStore("users", {keyPath: "id"});   
    3. for (var i in userData) {   
    4. objectStore.add(userData[i]);    
    5. }   
    6. }  

    我们使用createObjectStore()方法创建一个对象存储。 此方法接受两个参数:

    • 存储的名称和参数对象。 在这里,我们有一个名为"users"的对象存储,并定义了keyPath,这是对象唯一性的属性。 在这里,我们使用“id”作为keyPath,这个值在对象存储中是唯一的,我们必须确保该“ID”的属性在对象存储中的每个对象中存在。 一旦创建了对象存储,我们可以开始使用for循环添加数据进去。
       
      手动将数据添加到表:
      我们可以手动添加额外的数据到数据库中。

    JavaScript Code复制内容到剪贴板

    1. function Add() {   
    2. var request = db.transaction(["users"], "readwrite").objectStore("users")   
    3. .add({ id: "3", name: "Gautam", age: 30, email: "[email protected]" });   
    4.     
    5. request.onsuccess = function(e) {   
    6. alert("Gautam has been added to the database.");   
    7. };   
    8.     
    9. request.onerror = function(e) {   
    10. alert("Unable to add the information.");    
    11. }   
    12.     
    13. }  

    之前我们在数据库中做任何的CRUD操作(读,写,修改),必须使用事务。 该transaction()方法是用来指定我们想要进行事务处理的对象存储。 transaction()方法接受3个参数(第二个和第三个是可选的)。 第一个是我们要处理的对象存储的列表,第二个指定我们是否要只读/读写,第三个是版本变化。
     
    从表中读取数据 get()方法用于从对象存储中检索数据。 我们之前已经设置对象的id作为的keyPath,所以get()方法将查找具有相同id值的对象。 下面的代码将返回我们命名为“Bidulata”的对象:

    JavaScript Code复制内容到剪贴板

    1. function Read() {   
    2. var objectStore = db.transaction(["users"]).objectStore("users");   
    3. var request = objectStore.get("2");   
    4. request.onerror = function(event) {   
    5. alert("Unable to retrieve data from database!");   
    6. };   
    7. request.onsuccess = function(event) {    
    8. if(request.result) {   
    9. alert("Name: "   request.result.name   ", Age: "   request.result.age   ", Email: "   request.result.email);   
    10. } else {   
    11. alert("Bidulata couldn't be found in your database!");    
    12. }   
    13. };   
    14. }  

     
    从表中读取所有数据
    下面的方法检索表中的所有数据。 这里我们使用游标来检索对象存储中的所有数据:

    JavaScript Code复制内容到剪贴板

    1. function ReadAll() {   
    2. var objectStore = db.transaction("users").objectStore("users");    
    3. var req = objectStore.openCursor();   
    4. req.onsuccess = function(event) {   
    5. db.close();   
    6. var res = event.target.result;   
    7. if (res) {   
    8. alert("Key "   res.key   " is "   res.value.name   ", Age: "   res.value.age   ", Email: "   res.value.email);   
    9. res.continue();   
    10. }   
    11. };   
    12. req.onerror = function (e) {   
    13. console.log("Error Getting: ", e);   
    14. };    
    15. }  

    该openCursor()用于遍历数据库中的多个记录。 在continue()函数中继续读取下一条记录。
    删除表中的记录 下面的方法从对象中删除记录。

    JavaScript Code复制内容到剪贴板

    1. function Remove() {    
    2. var request = db.transaction(["users"], "readwrite").objectStore("users").delete("1");   
    3. request.onsuccess = function(event) {   
    4. alert("Tapas's entry has been removed from your database.");   
    5. };   
    6. }  

    我们要将对象的keyPath作为参数传递给delete()方法。
     
    最终代码
    下面的方法从对象源中删除一条记录:

    JavaScript Code复制内容到剪贴板

    1. <!DOCTYPE html>  
    2. <head>  
    3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
    4. <title>IndexedDB</title>  
    5. <script type="text/javascript">  
    6. var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;   
    7.     
    8. //prefixes of window.IDB objects   
    9. var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;   
    10. var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange   
    11.     
    12. if (!indexedDB) {   
    13. alert("Your browser doesn't support a stable version of IndexedDB.")   
    14. }   
    15. var customerData = [   
    16. { id: "1", name: "Tapas", age: 33, email: "[email protected]" },   
    17. { id: "2", name: "Bidulata", age: 55, email: "[email protected]" }   
    18. ];   
    19. var db;   
    20. var request = indexedDB.open("newDatabase", 1);   
    21.     
    22. request.onerror = function(e) {   
    23. console.log("error: ", e);   
    24. };   
    25.     
    26. request.onsuccess = function(e) {   
    27. db = request.result;   
    28. console.log("success: "  db);   
    29. };   
    30.     
    31. request.onupgradeneeded = function(event) {   
    32.     
    33. }   
    34. request.onupgradeneeded = function(event) {   
    35. var objectStore = event.target.result.createObjectStore("users", {keyPath: "id"});   
    36. for (var i in userData) {   
    37. objectStore.add(userData[i]);    
    38. }   
    39. }   
    40. function Add() {   
    41. var request = db.transaction(["users"], "readwrite")   
    42. .objectStore("users")   
    43. .add({ id: "3", name: "Gautam", age: 30, email: "[email protected]" });   
    44.     
    45. request.onsuccess = function(e) {   
    46. alert("Gautam has been added to the database.");   
    47. };   
    48.     
    49. request.onerror = function(e) {   
    50. alert("Unable to add the information.");    
    51. }   
    52.     
    53. }   
    54. function Read() {   
    55. var objectStore = db.transaction("users").objectStore("users");   
    56. var request = objectStore.get("2");   
    57. request.onerror = function(event) {   
    58. alert("Unable to retrieve data from database!");   
    59. };   
    60. request.onsuccess = function(event) {    
    61. if(request.result) {   
    62. alert("Name: "   request.result.name   ", Age: "   request.result.age   ", Email: "   request.result.email);   
    63. } else {   
    64. alert("Bidulata couldn't be found in your database!");    
    65. }   
    66. };   
    67. }   
    68. function ReadAll() {   
    69. var objectStore = db.transaction("users").objectStore("users");    
    70. var req = objectStore.openCursor();   
    71. req.onsuccess = function(event) {   
    72. db.close();   
    73. var res = event.target.result;   
    74. if (res) {   
    75. alert("Key "   res.key   " is "   res.value.name   ", Age: "   res.value.age   ", Email: "   res.value.email);   
    76. res.continue();   
    77. }   
    78. };   
    79. req.onerror = function (e) {   
    80. console.log("Error Getting: ", e);   
    81. };    
    82. }   
    83. function Remove() {    
    84. var request = db.transaction(["users"], "readwrite").objectStore("users").delete("1");   
    85. request.onsuccess = function(event) {   
    86. alert("Tapas's entry has been removed from your database.");   
    87. };   
    88. }   
    89. </script>  
    90. </head>  
    91.     
    92. <body>  
    93. <button onclick="Add()">Add record</button>  
    94. <button onclick="Remove()">Delete record</button>  
    95. <button onclick="Read()">Retrieve single record</button>  
    96. <button onclick="ReadAll()">Retrieve all records</button>  
    97. </body>  
    98. </html>  

    localStorage是不带lock功能的。那么要实现前端的数据共享并且需要lock功能那就需要使用其它本储存方式,比如indexedDB。indededDB使用的是事务处理的机制,那实际上就是lock功能。
      做这个测试需要先简单的封装下indexedDB的操作,因为indexedDB的连接比较麻烦,而且两个测试页面都需要用到

    JavaScript Code复制内容到剪贴板

    1. //db.js   
    2. //封装事务操作   
    3. IDBDatabase.prototype.doTransaction=function(f){   
    4.   f(this.transaction(["Obj"],"readwrite").objectStore("Obj"));   
    5. };   
    6. //连接数据库,成功后调用main函数   
    7. (function(){   
    8.   //打开数据库   
    9.   var cn=indexedDB.open("TestDB",1);   
    10.   //创建数据对象   
    11.   cn.onupgradeneeded=function(e){   
    12.     e.target.result.createObjectStore("Obj");   
    13.   };   
    14.   //数据库连接成功   
    15.   cn.onsuccess=function(e){   
    16.     main(e.target.result);   
    17.   };   
    18. })();   
    19.   接着是两个测试页面   
    20. <script src="db.js"></script>  
    21. <script>  
    22. //a.html   
    23. function main(e){   
    24.   (function callee(){   
    25.     //开始一个事务   
    26.     e.doTransaction(function(e){   
    27.       e.put(1,"test"); //设置test的值为1   
    28.       e.put(2,"test"); //设置test的值为2   
    29.     });   
    30.     setTimeout(callee);   
    31.   })();   
    32. };   
    33. </script>  
    34. <script src="db.js"></script>  
    35. <script>  
    36. //b.html   
    37. function main(e){   
    38.   (function callee(){   
    39.     //开始一个事务   
    40.     e.doTransaction(function(e){   
    41.       //获取test的值   
    42.       e.get("test").onsuccess=function(e){   
    43.         console.log(e.target.result);   
    44.       };   
    45.     });   
    46.     setTimeout(callee);   
    47.   })();   
    48. };   
    49. </script>  

    把localStorage换成了indexedDB事务处理。但是结果就不同

    图片 1

    测试的时候b.html中可能不会立即有输出,因为indexedDB正忙着处理a.html东西,b.html事务丢在了事务丢队列中等待。但是无论如何,输出结果也不会是1这个值。因为indexedDB的最小处理单位是事务,而不是localStorage那样以表达式为单位。这样只要把lock和unlock之间需要处理的东西放入一个事务中即可实现。另外,浏览器对indexedDB的支持不如localStorage,所以使用时还得考虑浏览器兼容。

    这篇文章主要介绍了深入解析HTML5中的IndexedDB索引数据库,包括事务锁等基本功能的相关使...

    本文由 伯乐在线 - njuyz 翻译。未经许可,禁止转载!
    英文出处:Nettuts 。欢迎加入翻译组。

    一、使用indexedDB的基本模式

    1. 打开数据库并且开始一个事务。
    2. 创建一个 objecStore
    3. 构建一个请求来执行一些数据库操作,像增加或提取数据等。
    4. 通过监听正确类型的 DOM 事件以等待操作完成。
    5. 在操作结果上进行一些操作(可以在 request 对象中找到)

    使用方式

    为了提升Web应用的用户体验,想必很多开发者都会项目中引入离线数据存储机制。可是面对各种各样的离线数据技术,哪一种才是最能满足项目需求的呢?本文将帮助各位找到最合适的那一个。

    二、创建、打开数据库

    indexedDB 存在于全局对象window上, 它最重要的一个方法就是open方法, 该方法接收两个参数:

    • dbName // 数据库名称 [string]
    • version // 数据库版本 [整型number]

    var DB_NAME = 'indexedDB-test', VERSION = 1, db; var request = indexedDB.open(DB_NAME, VERSION); request.onsuccess = function(event) { db = event.target.result; // console.log(event.target === request); // true db.onsuccess = function(event) { console.log('数据库操作成功!'); }; db.onerror = function(event) { console.error('数据库操作发生错误!', event.target.errorCode); }; console.log('打开数据库成功!'); }; request.onerror = function(event) { console.error('创建数据库出错'); console.error('error code:', event.target.errorCode); }; request.onupgradeneeded = function(event) { // 更新对象存储空间和索引 .... };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var DB_NAME = 'indexedDB-test', VERSION = 1, db;
    var request = indexedDB.open(DB_NAME, VERSION);
    request.onsuccess = function(event) {
        db = event.target.result;
        // console.log(event.target === request); // true
        db.onsuccess = function(event) {
            console.log('数据库操作成功!');
        };
        db.onerror = function(event) {
            console.error('数据库操作发生错误!', event.target.errorCode);
        };
        console.log('打开数据库成功!');
    };
    request.onerror = function(event) {
        console.error('创建数据库出错');
        console.error('error code:', event.target.errorCode);
    };
    request.onupgradeneeded = function(event) {
       // 更新对象存储空间和索引 ....
    };

    若是本域下不存在名为DB_NAME的数据库,则上述代码会创建一个名为DB_NAME、版本号为VERSION的数据库; 触发的事件依次为: upgradeneededsuccess.

    若是已存在名为DB_NAME的数据库, 则上述代码会打开该数据库; 只触发success/error事件,不会触发upgradeneeded事件. db是对该数据库的引用.

    连接数据库

    要使用它必须先打开,通过 indexDB.open(name, version)方法打开一个数据库

    • name : 表示数据要打开的数据库的名称
    • version:为打开数据库的版本号

    引言

    随着HTML5的到来,各种Web离线数据技术进入了开发人员的视野。诸如AppCache、localStorage、sessionStorage和IndexedDB等等,每一种技术都有它们各自适用的范畴。比如AppCache就比较适合用于离线起动应用,或者在离线状态下使应用的一部分功能照常运行。接下来我将会为大家作详细介绍,并且用一些代码片段来展示如何使用这些技术。

    三、创建对象存储空间和索引

    在关系型数据库(如mysql)中,一个数据库中会有多张表,每张表有各自的主键、索引等;

    key-value型数据库(如indexedDB)中, 一个数据库会有多个对象存储空间,每个存储空间有自己的主键、索引等;

    创建对象存储空间的操作一般放在创建数据库成功回调里:

    request.onupgradeneeded = function(event) { // 更新对象存储空间和索引 .... var database = event.target.result; var objectStore = database.createObjectStore("movies", { keyPath: "id" }); objectStore.createIndex('alt', 'alt', { unique: true }); objectStore.createIndex('title', 'title', { unique: false }); };

    1
    2
    3
    4
    5
    6
    request.onupgradeneeded = function(event) { // 更新对象存储空间和索引 ....
        var database = event.target.result;
        var objectStore = database.createObjectStore("movies", { keyPath: "id" });
        objectStore.createIndex('alt', 'alt', { unique: true });
        objectStore.createIndex('title', 'title', { unique: false });
    };

    图片 2

    onupgradeneeded 是我们唯一可以修改数据库结构的地方。在这里面,我们可以创建和删除对象存储空间以及构建和删除索引。

    在数据库对象database上,有以下方法可供调用:

    1. createObjectStore(storeName, configObj) 创建一个对象存储空间
      • storeName // 对象存储空间的名称 [string]
      • configObj // 该对象存储空间的配置 [object] (其中的keyPath属性值,标志对象的该属性值唯一)
    2. createIndex(indexName, objAttr, configObj) 创建一个索引
      • indexName // 索引名称 [string]
      • objAttr // 对象的属性名 [string]
      • configObj // 该索引的配置对象 [object]

    indexDB.open()方法的原理

    分为两种情况:
    1. 传入的数据库不存在
    当传入的数据库不存在时,该方法就会创建一个名为name的数据库,并打开它,此时,会先触发upgradeneeded事件;调用该函数会返回一个IDBRequest对象,可以在该对象上添加onsuccess事件onerror事件
    注意:当打开一个不存在的数据库时会触发upgradeneeded事件,这是触发该事件的一种途径,为什么会触发该事件呢?该事件有什么作用?留个疑问在这儿,等会解答。

    2. 传入的数据库存在
    这里分为两种情况:

    • 当传入的数据库存在,且version版本号与将要打开的数据库版本号也相同
      则直接打开该数据库,如果成功,则会触发onsuccess事件,失败则触发onerror事件
      注意:这里并不会触发upgradeneeded事件,为什么?留个疑问

    • 当传入的数据库存在,但是传入的version版本号高于将要打开的数据库的版本号
      则直接打开该数据库,同时触发upgradeneeded事件,然后再触发onsuccess事件onerror事件,这里也触发了onupdateneeded事件

    AppCache

    如果你的Web应用中有一部分功能(或者整个应用)需要在脱离服务器的情况下使用,那么就可以通过AppCache来让你的用户在离线状态下也能使用。你所需要做的就是创建一个配置文件,在其中指定哪些资源需要被缓存,哪些不需要。此外,还能在其中指定某些联机资源在脱机条件下的替代资源。

    AppCache的配置文件通常是一个以.appcache结尾的文本文件(推荐写法)。文件以CACHE MANIFEST开头,包含下列三部分内容:

    • CACHE – 指定了哪些资源在用户第一次访问站点的时候需要被下载并缓存
    • NETWORK – 指定了哪些资源需要在联机条件下才能访问,这些资源从不被缓存
    • FALLBACK – 指定了上述资源在脱机条件下的替代资源

    四、增加和删除数据

    对数据库的操作(增删查改等)都需要通过事务来完成,事务具有三种模式:

    • readonly 只读(可以并发进行,优先使用)
    • readwrite 读写
    • versionchange 版本变更

    upgradeneeded事件

    触发该事件的条件:当打开的数据库不存在,或者传入的数据库版本version高于当前版本,则会触发该事件

    upgradeneeded事件的作用:当打开了一个数据库之后,需要开辟一个名为:对象存储空间 的玩意(可以理解为数据就是存放在这个空间里面,一个数据库可以创建多个对象存储空间),而 对象存储空间 只能在upgradeneeded事件的处理函数中创建

    使用时,注意以下两种情况:

    1. 当我们第一次打开创建数据库时,会触发upgradeneeded事件,我们就需要在其中创建对象存储空间

    2. 当我们对数据库版本进行更新时,也会触发该事件,这时可以在此创建新的对象存储空间,原来的对象存储空间仍然存在

    注意:如果需要对对象存储空间进行修改,那么只能先将存储在它里面的数据读取出来,再将其删除,然后使用新的选项去创建它,再写入原来的数据

    打开数据库并创建对象存储空间的代码:

    // 对于该API,各浏览器还未同一,所以需要对一些接口添加前缀
    window.indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
    window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
    window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
    window.IDBCursor = window.IDBCursor || window.webkitIDBTransaction;
    
    // 判断浏览器是否支持IndexedDB
    if (!window.indexedDB) {
    window.alert("Your browser doesn't support a stable version of IndexedDB.")
    }
    
    var request , db;
    // 打开或创建 名为dbName的数据库
    request = window.indexedDB.open('dbName', 2)
    request.onsuccess = function (event) {
       db = event.target.result;
    }
    
    request.onerror = function (event) {
       console.log('错误代码: '   event.target.errorCode);
    }
    
    request.onupgradeneeded = function(event) {
      db = event.target.result;  // 
      // 创建一个   对象存储空间,名为customers
      var objectStore = db.createObjectStore('customers', {keyPath: 'ssn'});
      // 对于某些数据,可以为一个对象存储空间指定多个键。比如,若要通过用户ID 和用户名 两种方式来保存用户资料,就需要通过两个键来存取记录
      // 因此可以使用createIndex,名字是有可能重复的,所以其unique 设置为 false ;第一个name是索引的名字,该名字是索引的名字,第二个name是索引的属性的名字,该名字要与对象中的属性相同
      objectStore.createIndex('name', 'name', { unique: false});
    
      // 创建一个email的索引,该email是独特的,所以 unique 设置为 true
      objectStore.createIndex('email', 'email', { unique: true});
    }
    

    示例

    首先,你需要在页面上指定AppCache的配置文件:

    XHTML

    <!DOCTYPE html> <html manifest="manifest.appcache"> ... </html>

    1
    2
    3
    4
    <!DOCTYPE html>
    <html manifest="manifest.appcache">
    ...
    </html>

    在这里千万记得在服务器端发布上述配置文件的时候,需要将MIME类型设置为text/cache-manifest,否则浏览器无法正常解析。

    接下来是创建之前定义好的各种资源。我们假定在这个示例中,你开发的是一个交互类站点,用户可以在上面联系别人并且发表评论。用户在离线的状态下依然可以访问网站的静态部分,而联系以及发表评论的页面则会被其它页面替代,无法访问。

    好的,我们这就着手定义那些静态资源:

    JavaScript

    CACHE MANIFEST CACHE: /about.html /portfolio.html /portfolio_gallery/image_1.jpg /portfolio_gallery/image_2.jpg /info.html /style.css /main.js /jquery.min.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    CACHE MANIFEST
     
    CACHE:
    /about.html
    /portfolio.html
    /portfolio_gallery/image_1.jpg
    /portfolio_gallery/image_2.jpg
    /info.html
    /style.css
    /main.js
    /jquery.min.js

    旁注:配置文件写起来有一点很不方便。举例来说,如果你想缓存整个目录,你不能直接在CACHE部分使用通配符(*),而是只能在NETWORK部分使用通配符把所有不应该被缓存的资源写出来。

    你不需要显式地缓存包含配置文件的页面,因为这个页面会自动被缓存。接下来我们为联系和评论的页面定义FALLBACK部分:

    JavaScript

    FALLBACK: /contact.html /offline.html /comments.html /offline.html

    1
    2
    3
    FALLBACK:
    /contact.html /offline.html
    /comments.html /offline.html

    最后我们用一个通配符来阻止其余的资源被缓存:

    JavaScript

    NETWORK: *

    1
    2
    NETWORK:
    *

    最后的结果就是下面这样:

    JavaScript

    CACHE MANIFEST CACHE: /about.html /portfolio.html /portfolio_gallery/image_1.jpg /portfolio_gallery/image_2.jpg /info.html /style.css /main.js /jquery.min.js FALLBACK: /contact.html /offline.html /comments.html /offline.html NETWORK: *

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    CACHE MANIFEST
     
    CACHE:
    /about.html
    /portfolio.html
    /portfolio_gallery/image_1.jpg
    /portfolio_gallery/image_2.jpg
    /info.html
    /style.css
    /main.js
    /jquery.min.js
     
    FALLBACK:
    /contact.html /offline.html
    /comments.html /offline.html
     
    NETWORK:
    *

    还有一件很重要的事情要记得:你的资源只会被缓存一次!也就是说,如果资源更新了,它们不会自动更新,除非你修改了配置文件。所以有一个最佳实践是,在配置文件中增加一项版本号,每次更新资源的时候顺带更新版本号:

    JavaScript

    CACHE MANIFEST # version 1 CACHE: ...

    1
    2
    3
    4
    5
    6
    CACHE MANIFEST
     
    # version 1
     
    CACHE:
    ...

    向数据库中增加数据

    前面提到,增加数据需要通过事务事务的使用方式如下:

    var transaction = db.transaction(['movies'], 'readwrite'); transaction.oncomplete = function(event) { console.log('事务完成!'); }; transaction.onerror = function(event) { console.log('事务失败!', event.target.errorCode); }; transaction.onabort = function(event) { console.log('事务回滚!'); };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var transaction = db.transaction(['movies'], 'readwrite');
    transaction.oncomplete = function(event) {
        console.log('事务完成!');
    };
    transaction.onerror = function(event) {
        console.log('事务失败!', event.target.errorCode);
    };
    transaction.onabort = function(event) {
        console.log('事务回滚!');
    };

    图片 3数据库对象的transaction()方法接收两个参数:

    • storeNames // 对象存储空间,可以是对象存储空间名称的数组,也可以是单个对象存储空间名称,必传 [array|string]
    • mode // 事务模式,上面提到的三种之一,可选,默认值是readonly [string]

    这样,我们得到一个事务对象transaction, 有三种事件可能会被触发: complete, error, abort. 现在,我们通过事务向数据库indexedDB-test的 对象存储空间movies中插入数据:

    var objectStore = transaction.objectStore('movies'); // 指定对象存储空间 var data = [{ "title": "寻梦环游记", "year": "2017", "alt": "", "id": "20495023" }, { "title": "你在哪", "year": "2016", "alt": "", "id": "26639033" }, { "title": "笔仙咒怨", "year": "2017", "alt": "", "id": "27054612" }]; data.forEach(function(item, index){ var request = objectStore.add(item); request.onsuccess = function(event) { console.log('插入成功!', index); console.log(event.target.result, item.id); // add()方法调用成功后result是被添加的值的键(id) }; });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    var objectStore = transaction.objectStore('movies');  // 指定对象存储空间
    var data = [{
      "title": "寻梦环游记",
      "year": "2017",
      "alt": "https://movie.douban.com/subject/20495023/",
      "id": "20495023"
    }, {
      "title": "你在哪",
      "year": "2016",
      "alt": "https://movie.douban.com/subject/26639033/",
      "id": "26639033"
    }, {
      "title": "笔仙咒怨",
      "year": "2017",
      "alt": "https://movie.douban.com/subject/27054612/",
      "id": "27054612"
    }];
    data.forEach(function(item, index){
        var request = objectStore.add(item);
        request.onsuccess = function(event) {
            console.log('插入成功!', index);
            console.log(event.target.result, item.id); // add()方法调用成功后result是被添加的值的键(id)
        };
    });

    图片 4

    通过事务对象transaction,在objectStore()方法中指定对象存储空间,就得到了可以对该对象存储空间进行操作的对象objectStore.

    向数据库中增加数据,add()方法增加的对象,若是数据库中已存在相同的主键,或者唯一性索引的键值重复,则该条数据不会插入进去;

    增加数据还有一个方法: put(), 使用方法和add()不同之处在于,数据库中若存在相同主键或者唯一性索引重复,则会更新该条数据,否则插入新数据。

    存储数据

    存储数据有两种方法:add()方法put()方法

    这两种方法的区别主要体现在:当要添加数据的对象存储空间中已经存在有相同键的数据时,使用add()方法添加数据会报错误,而put()方法则会对现有数据进行更新,所以add()方法一般用于初始化数据,而put()方法用于更新数据

    代码如下:

    // customerData 为要存储的数据
    const customerData = [{ ssn: '444-44-4444', name: 'AAA', age: 35, email: '[AAA@company.com](mailto:AAA@company.com)'},{ ssn: '666-66-6666', name: 'CCC', age: 35, email: '[CCC@company.com](mailto:CCC@company.com)'},{ ssn: '777-77-7777', name: 'DDD', age: 32, email: '[DDD@home.org](mailto:DDD@home.org)'},{ ssn: '555-55-5555', name: 'BBB', age: 32, email: '[BBB@home.org](mailto:BBB@home.org)'},
    ];
    
    // 创建一个事务,该事务将要对名为“customers”的对象存储空间进行 read和write 操作,并返回事务索引
    let transaction = db.transaction('customers', 'readwrite'); 
    
    // 取得索引后,使用objectStore()方法并传入存储空间的名称,就可以访问特定的存储空间,这两步是必须的
    let store = transaction.objectStore('customers'); 
    
    // 添加数据到数据库中
    for (var i in customerData) {
      // 返回的req也是一个对象,可以为其添加onsuccess和onerror事件,来检测数据是否添加成功
      let req = store.put(customerData[i]);   // 往一个存储空间中添加数据
    
    }
    // 判断事务整个操作完成
    transaction.oncomplete = function(event) {
      console.log(event.target);
      alert('存储数据完成');
    };
    }
    

    如上就将数据存储到数据库dbNames的customers对象存储空间中

    上面代码中提到了 [事务],这里先记住:凡是涉及到对数据库的读写删除操作,都需要通过 [事务] 来完成

    LocalStorage和SessionStorage

    如果你想在Javascript代码里面保存些数据,那么这两个东西就派上用场了。前一个可以保存数据,永远不会过期(expire)。只要是相同的域和端口,所有的页面中都能访问到通过LocalStorage保存的数据。举个简单的例子,你可以用它来保存用户设置,用户可以把他的个人喜好保存在当前使用的电脑上,以后打开应用的时候能够直接加载。后者也能保存数据,但是一旦关闭浏览器窗口(译者注:浏览器窗口,window,如果是多tab浏览器,则此处指代tab)就失效了。而且这些数据不能在不同的浏览器窗口之间共享,即使是在不同的窗口中访问同一个Web应用的其它页面。

    旁注:有一点需要提醒的是,LocalStorage和SessionStorage里面只能保存基本类型的数据,也就是字符串和数字类型。其它所有的数据可以通过各自的toString()方法转化后保存。如果你想保存一个对象,则需要使用JSON.stringfy方法。(如果这个对象是一个类,你可以复写它默认的toString()方法,这个方法会自动被调用)。

    从数据库中删除数据

    删除数据使用delete方法,同上类似:

    var request = db.transaction(['movies'], 'readwrite') .objectStore('movies') .delete('27054612'); // 通过键id来删除 request.onsuccess = function(event) { console.log('删除成功!'); console.log(event.target.result); };

    1
    2
    3
    4
    5
    6
    7
    8
    var request =
        db.transaction(['movies'], 'readwrite')
          .objectStore('movies')
          .delete('27054612');  // 通过键id来删除
    request.onsuccess = function(event) {
        console.log('删除成功!');
        console.log(event.target.result);
    };

     

    事务和查询操作数据

    最简单的创建事务的方式是:
    var transaction = db.transaction(); // db就是前面的数据库对象
    这种方式创建的事务,只能读取数据库中保存的所有对象

    一般用法是:
    var transaction = db.transaction('customes', 'readwrite');
    表示只加载customers对象存储空间中的数据,并且是以可读可写的方式加载

    如果不传第二个参数,则表示只可访问,不可修改;

    这里返回的transaction是事务的索引

    然后使用objectStore()方法并传入对象存储空间的名称,就可以访问特定的存储空间了;

    如下:

    let transaction = db.transaction('customers', 'readwrite'); 
    let store = transaction.objectStore('customers'); 
    

    取得了上面的store后,我们可以使用如下方法对数据进行操作:

    • add()和put()方法:用于存储数据
      let req = store.add(data);
    • get(key)方法:获取键为key的对象
      let req = store.get(key);
    • delete(key)方法:删除键为key的对象
      let req = store.delete(key);
    • clear()方法:清空对象存储空间中的所有对象
      let req = store.clear();
      使用上述方法会返回一个对象,通过对其添加onsuccess和onerror事件,可以检测操作是否成功

    注意:通过oncomplete事件对象,访问不到get()请求返回的任何数据,必须在响应请求的onsuccess事件处理程序中才能访问到数据

    示例

    我们不妨来看看之前的例子。在联系人和评论的部分,我们可以随时保存用户输入的东西。这样一来,即使用户不小心关闭了浏览器,之前输入的东西也不会丢失。对于jQuery来说,这个功能是小菜一碟。(注意:表单中每个输入字段都有id,在这里我们就用id来指代具体的字段)

    JavaScript

    $('#comments-input, .contact-field').on('keyup', function () { // let's check if localStorage is supported if (window.localStorage) { localStorage.setItem($(this).attr('id'), $(this).val()); } });

    1
    2
    3
    4
    5
    6
    $('#comments-input, .contact-field').on('keyup', function () {
       // let's check if localStorage is supported
       if (window.localStorage) {
          localStorage.setItem($(this).attr('id'), $(this).val());
       }
    });

    每次提交联系人和评论的表单,我们需要清空缓存的值,我们可以这样处理提交(submit)事件:

    JavaScript

    $('#comments-form, #contact-form').on('submit', function () { // get all of the fields we saved $('#comments-input, .contact-field').each(function () { // get field's id and remove it from local storage localStorage.removeItem($(this).attr('id')); }); });

    1
    2
    3
    4
    5
    6
    7
    $('#comments-form, #contact-form').on('submit', function () {
       // get all of the fields we saved
       $('#comments-input, .contact-field').each(function () {
          // get field's id and remove it from local storage
          localStorage.removeItem($(this).attr('id'));
       });
    });

    最后,每次加载页面的时候,把缓存的值填充到表单上即可:

    JavaScript

    // get all of the fields we saved $('#comments-input, .contact-field').each(function () { // get field's id and get it's value from local storage var val = localStorage.getItem($(this).attr('id')); // if the value exists, set it if (val) { $(this).val(val); } });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // get all of the fields we saved
    $('#comments-input, .contact-field').each(function () {
       // get field's id and get it's value from local storage
       var val = localStorage.getItem($(this).attr('id'));
       // if the value exists, set it
       if (val) {
          $(this).val(val);
       }
    });

    从数据中获取数据

    获取数据使用get方法,同上类似:

    var request = db.transaction('movies') .objectStore('movies') .get('9999682'); // 通过键alt来获取 request.onsuccess = function(event) { console.log('获取成功!', event.target.result); };

    1
    2
    3
    4
    5
    6
    7
    var request =
        db.transaction('movies')
           .objectStore('movies')
           .get('9999682');  // 通过键alt来获取
    request.onsuccess = function(event) {
        console.log('获取成功!', event.target.result);
    };

    使用游标查询数据

    使用事务可以直接通过 已知的键检索单个对象。而在需要检索多个对象时,则需要在事务内创建游标。

    游标并不会提前收集结果,游标先指向结果中的第一项,在接到查找下一项的指令时,才会指向下一项

    如下:

    let transaction = db.transaction('customers', 'readwrite'),
    let store = transaction.objectStore('customers'),
    let request = store.openCursor(null) ; // 这里创建游标
    request.onsuccess = function (event) {
      // event.target.result 中保存的是在存储空间中查询到的对象
      // event.target.result 中有几个属性值,可以了解到查询到的对象中的细节,
      // key: 当前访问的对象的键
      // value:当前访问的实际对象
      // primaryKey: 游标使用的键
      // direction:数值,表示游标移动的方向
      let cursor = event.target.result;
      let value, updateRequest, deleteRequest;
    
      // 这里必须要检查游标中是否有数据
      if (cursor) {
        if (cursor.key === '555-55-5555') {
          value = cursor.value;   // 获取到实际的访问对象
          value.name = 'hexon';   // 修改对象的name属性
          // 调用update()方法可以用指定的对象,更新对象的value
          updateRequest = cursor.update(value);     
          updateRequest.onsuccess = function() {
              // 处理成功
           }
        }
        cursor.continue() ;  // 移动到下一项,会触发下一次请求,同时成功则触发request.onsuccess
      }
    }
    

    上面例子中,可以使用cursor.delete()方法删除当前项

    IndexedDB

    在我个人看来,这是最有意思的一种技术。它可以保存大量经过索引(indexed)的数据在浏览器端。这样一来,就能在客户端保存复杂对象,大文档等等数据。而且用户可以在离线情况下访问它们。这一特性几乎适用于所有类型的Web应用:如果你写的是邮件客户端,你可以缓存用户的邮件,以供稍后再看;如果你写的是相册类应用,你可以离线保存用户的照片;如果你写的是GPS导航,你可以缓存用户的路线……不胜枚举。

    IndexedDB是一个面向对象的数据库。这就意味着在IndexedDB中既不存在表的概念,也没有SQL,数据是以键值对的形式保存的。其中的键既可以是字符串和数字等基础类型,也可以是日期和数组等复杂类型。这个数据库本身构建于存储(store,一个store类似于关系型数据中表的概念)的基础上。数据库中每个值都必须要有对应的键。每个键既可以自动生成,也可以在插入值的时候指定,也可以取自于值中的某个字段。如果你决定使用值中的字段,那么只能向其中添加Javascript对象,因为基础数据类型不像Javascript对象那样有自定义属性。

    五、使用索引

    在前面,我们创建了两个索引alttitle, 配置对象里面的unique属性标志该值是否唯一

    现在我们想找到alt属性值为https://movie.douban.com/subject/26639033/的对象,就可以使用索引。

    var alt = ''; var objectStore = db.transaction('movies').objectStore('movies'); // 打开对象存储空间 var index = objectStore.index('alt'); // 使用索引'alt' var request = index.get(alt); // 创建一个查找数据的请求 request.onsuccess = function(event) { console.log('The result is:', event.target.result); }; var noDataTest = index.get('testalt'); // 没有该对象时的测试 noDataTest.onsuccess = function(event) { console.log('success! result:', event.target.result); }; noDataTest.onerror = function(event) { console.log('error! event:', event); };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var alt = 'https://movie.douban.com/subject/26639033/';
    var objectStore = db.transaction('movies').objectStore('movies');  // 打开对象存储空间
    var index = objectStore.index('alt');  // 使用索引'alt'
    var request = index.get(alt);          // 创建一个查找数据的请求
    request.onsuccess = function(event) {
        console.log('The result is:', event.target.result);
    };
    var noDataTest = index.get('testalt');  // 没有该对象时的测试
    noDataTest.onsuccess = function(event) {
        console.log('success! result:', event.target.result);
    };
    noDataTest.onerror = function(event) {
        console.log('error! event:', event);
    };

    图片 5

    使用唯一性索引,我们可以得到唯一的一条数据(或者undefined),那么使用非唯一性索引呢?
    我们向数据库中插入一条数据,使title重复:

    db.transaction('movies', 'readwrite').objectStore('movies') .add({ alt: '', title: '寻梦环游记', year: '2017', id: '123456789' }) .onsuccess = function(event) { console.log('插入成功!'); };

    1
    2
    3
    4
    5
    6
    7
    db.transaction('movies', 'readwrite').objectStore('movies')
    .add({ alt: 'https://movie.douban.com/subject/27054612121/',
        title: '寻梦环游记',
        year: '2017',
        id: '123456789'
    })
    .onsuccess = function(event) { console.log('插入成功!'); };

    使用索引title获取title值为寻梦环游记的对象:

    var indexName = 'title', title = '寻梦环游记'; var objectStore = db.transaction('movies').objectStore('movies'); var index = objectStore.index(indexName); // 使用索引'alt' var request = index.get(title); // 创建一个查找数据的请求 request.onsuccess = function(event) { console.log('The result is:', event.target.result); };

    1
    2
    3
    4
    5
    6
    7
    var indexName = 'title', title = '寻梦环游记';
    var objectStore = db.transaction('movies').objectStore('movies');
    var index = objectStore.index(indexName);  // 使用索引'alt'
    var request = index.get(title);          // 创建一个查找数据的请求
    request.onsuccess = function(event) {
        console.log('The result is:', event.target.result);
    };

    图片 6

    我们得到的是键值最小的那个对象.

    使用一次索引,我们只能得到一条数据; 如果我们需要得到所有title属性值为寻梦环游记的对象,我们可以使用游标.

    键范围

    游标也可以接受一个键,也就是通过键来设定游标查找的范围;
    代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>WebStorage DEMO</title>
    </head>
    <body>
    <div class="networkStatus">
    <button class="clear">清空数据</button>
    <button class="add">添加数据</button>
    <button class="query">查询数据</button>
    <button class="delete">删除数据</button>
    <button class="cursor">使用游标查询</button>
    <button class="keyRange">使用keyrange查询</button>
    <button class="index">使用index</button>
    </div>

    <script>
    let network = document.querySelector('.networkStatus'),
    addBtn = document.querySelector('.add'),
    queryBtn = document.querySelector('.query'),
    deleteBtn = document.querySelector('.delete'),
    cursorBtn = document.querySelector('.cursor'),
    clearBtn = document.querySelector('.clear'),
    keyRange = document.querySelector('.keyRange'),
    indexBtn = document.querySelector('.index')
    ;

    // 判断网路是否在线
    // if (navigator.onLine) {
    // network.innerText = "网络在线";
    // } else {
    // network.innerText = "网络掉线";
    // }

    // // 监控网络状态的事件:online 和 offline, 这两个事件在window对象上
    // window.addEventListener('online', () => {
    // network.innerText = "网络在线";
    // });

    // window.addEventListener('offline', () => {
    // network.innerText = "网络掉线";
    // });

    //--------cookie的使用---------------
    let CookieUtil = {
    get: (name) => {
    let cookieName = encodeURIComponent(name) "=",
    cookieStart = document.cookie.indexOf(cookieName),
    cookieValue = null;

      if (cookieStart > -1) {
        let cookieEnd = document.cookie.indexOf(';', cookieStart);
        if (cookieEnd === -1) {
          cookieEnd = document.cookie.length;
        }
        cookieValue = decodeURIComponent(document.cookie.substring(cookieStart   cookieName.length, cookieEnd));
      }
    
      return cookieValue;
    },
    set: function (name, value, expires, path, domain, secure) {
      let cookieText = encodeURIComponent(name)   '='  
                       encodeURIComponent(value);
    
      if (expires instanceof Date) {
        cookieText  = '; expires='   expires.toGMTString();
      }
    
      if (path) {
        cookieText  = '; path='   path;
      }
    
      if (domain) {
        cookieText  = '; domain='   domain;
      }
    
      if (secure) {
        cookieText  = '; secure';
      }
    
      document.cookie = cookieText;
    },
    
    // 删除cookie, 并没有直接的删除cookie的方法,这里通过重新设置cookie名称,来对cookie进行替换
    // 同时 将过期时间expires设置为过去的时间,
    unset: function(name, path, domain, secure) {
      this.set(name, '', new Date(0), path, domain, secure);
    }
    

    }

    CookieUtil.set('name', 'hexon');
    CookieUtil.set('book', 'Profession Javascript');

    // 读取cookie的值
    // console.log(CookieUtil.get('name'));
    // console.log(CookieUtil.get('book'));

    // 删除cookie
    基本使用,Web应用中的离线数据存储。CookieUtil.unset('name');
    CookieUtil.unset('book');

    // 设置cookie, 包括它的路径、域、失效日期
    CookieUtil.set('name', 'Hexon', 'books/projs/', 'www.wrox.com', new Date('January 1, 2017'));

    // 删除刚刚设置的cookie
    CookieUtil.unset('name', 'books/projs/', 'www.www.wrox.com');

    // 设置安全的cookie
    CookieUtil.unset('name', 'hexon', null, null, null, null, true)

    // --- IndexedDB 数据库的使用
    var request = window.indexedDB.open('dbName', 2)
    var db;
    const dbName = 'the_name';
    // 创建一个数据
    const customerData = [
    { ssn: '444-44-4444', name: 'AAA', age: 35, email: 'AAA@company.com'},
    { ssn: '666-66-6666', name: 'CCC', age: 35, email: 'CCC@company.com'},
    { ssn: '777-77-7777', name: 'DDD', age: 32, email: 'DDD@home.org'},
    { ssn: '555-55-5555', name: 'BBB', age: 32, email: 'BBB@home.org'},

    ];

    window.indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
    window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
    window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
    window.IDBCursor = window.IDBCursor || window.webkitIDBTransaction;

    if (!window.indexedDB) {
    window.alert("Your browser doesn't support a stable version of IndexedDB.")
    }

    // 3 是建立的数据库版本,如果名为MyTestDatabase的数据库不存在,就会创造该数据库,然后 onupgradeneeded 事件会被触发;
    // 如果数据库存在,但是对版本升级了,也会触发onupgradeneeded事件,
    // 注意:版本号是一个 unsigned long long 类型的值,因此不要使用float,否则会将其转换为其最接近的整数

    // 生成处理程序
    request.onerror = function (event) {
    // do Something
    alert('Database error: ' event.target.errorCode);
    };

    request.onsuccess = function (event) {
    // do Something
    console.log('创建数据库成功');
    db = event.target.result; // 创建成功后,e.target.result 中存储的是IDBDatabase对象的实例
    }

    // 当创建一个新的数据库 或者 更新已存在数据库的版本, onupgradeneeded事件将会被触发,新的对象存储在event.target.result中。
    // 在该处理程序中,数据库已经具有先前版本的对象存储,因此不必再次创建这些对象存储,只需要创建任何我们需要的对象存储,或者
    // 从先前版本中删除不在需要的对象存储。如果需要更改当前对象存储,则必须先删除旧的对象存储,然后在使用新的选项创建。
    // 删除旧的对象存储,在其上的信息都会被删除;
    // 注意:该事件是唯一一个能够对数据库进行操作的地方,在该事件里面,你对对象存储进行删除、修改或移除索引
    request.onupgradeneeded = function(event) {
    console.log('onupgradeneeded');
    var db = event.target.result;

    // 创建一个   对象存储空间,名为customers
    var objectStore = db.createObjectStore('customers', {keyPath: 'ssn'});
    // 对于某些数据,可以为一个对象存储空间指定多个键。比如,若要通过用户ID 和用户名 两种方式来保存用户资料,就需要通过两个键来存取记录
    // 因此可以使用createIndex,名字是有可能重复的,所以其unique 设置为 false ;第一个name是索引的名字,该名字是索引的名字,第二个name是索引的属性的名字,该名字要与对象中的属性相同
    objectStore.createIndex('name', 'name', { unique: false});
    
    // // 创建一个email的索引,该email是独特的,所以 unique 设置为 true
    objectStore.createIndex('email', 'email', { unique: true});
    

    }

    function save(data) {
    /// 对于数据库的对象存储空间中数据的读取或修改数据,都要通过事物来组织所有操作
    // 最简单的创建事物的方法是:var transaction = db.transaction();
    let transaction = db.transaction('customers', 'readwrite'); // 创建一个事务,并定义该事务的操作为 “readwrite” ,并返回其索引
    let store = transaction.objectStore('customers'); // 取得索引后,使用objectStore()方法并传入存储空间的名称,就可以访问特定的存储空间

    for (var i in customerData) {
      let req = store.put(customerData[i]);   // 往一个存储空间中添加数据
    }
    
    transaction.oncomplete = function(event) {
      console.log(event.target);
      alert('存储数据完成');
    };
    
    transaction.onsuccess = function(event ) {
      console.log('onsuccess 事件');
    }
    

    }

    function clear() {
    // body...
    let transaction = db.transaction('customers', 'readwrite');
    let store = transaction.objectStore('customers').clear();
    store.onerror = function(event) {
    console.log('清空数据失败');
    }
    store.onsuccess = function(event) {
    console.log('清空数据成功');
    }
    }

    // 使用事务 直接通过已知的键索引 单个对象 (只能索引单个对象)
    function getData() {
    let transaction = db.transaction('customers', 'readwrite'); // 创建一个事物, 并定义该事务的操作为 "readonly"
    let store = transaction.objectStore('customers').get('444-44-4444'); // 使用get() 可以取得值

    store.onerror = function (event) {
      alert('did not get the object');
    }
    
    store.onsuccess = function (event) {
      var result = event.target.result;
      console.log(result);
      alert('获取数据完成! 年龄是: '   result.age);
    }
    

    }

    function deleteData() {
    let transaction = db.transaction('customers', 'readwrite');
    let store = transaction.objectStore('customers');
    store.delete('444-44-4444');
    alert('s删除数据完成');
    }

    // 在事务内创建游标查询 可以索引 多个对象(注意: 是多个对象)
    // 游标不提前手机结果
    function cursorQuery() {
    let transaction = db.transaction('customers', 'readwrite'),
    store = transaction.objectStore('customers'),
    request = store.openCursor(null) ; // 这里创建游标

    request.onsuccess = function (event) {
    
      // event.target.result 中保存的是在存储空间中查询到的对象
      // event.target.result 中有几个属性值,可以了解到查询到的对象中的细节,
      // key: 当前访问的对象的键
      // value:当前访问的实际对象
      // primaryKey: 游标使用的键
      // direction:数值,表示游标移动的方向
    
      let cursor = event.target.result;
      let value, updateRequest, deleteRequest;
      if (cursor) {
      //   if (cursor.key === '555-55-5555') {
      //     value = cursor.value;   // 获取到实际的访问对象
      //     value.name = 'hexon';   // 修改对象的name属性
    
      //     updateRequest = cursor.update(value);      // 调用update()方法可以用指定的对象,更新对象的value
      //     updateRequest.onsuccess = function() {
      //       // 处理成功
      //     }
      //     updateRequest.onerror = function() {
      //       // 处理失败
      //     }
    
    
      //     // 使用游标删除当前项
      //     // deleteRequest = cursor.delete();
      //     // deleteRequest.onsuccess = function() {
      //     //   // 删除成功处理
      //     // }
      //     // deleteRequest.onerror = function() {
      //     //   // 删除失败处理
      //     // }
    
    
      //   }
      //   console.log(event.target.result);
      // }
      console.log(cursor.value);
      cursor.continue();      // 移动到下一项,
      }
      request.onerror = function(event) {
        console.log('游标查询创建失败')
      }
    }
    

    }

    // 使用keyrange查询
    function keyRangeQuery() {
    let transaction = db.transaction('customers', 'readwrite')
    let store = transaction.objectStore('customers');
    // 使用bound()方法 定义键范围
    let range = IDBKeyRange.bound('555-55-5555', '777-77-7777', true, false);
    // 将键传入游标创建
    let request = store.openCursor(range);

    request.onsuccess = function(event) {
      let cursor = event.target.result;
      if (cursor) {
        console.log('游标查询到的值'   JSON.stringify(cursor.value));
        cursor.continue()     // 移动到下一项
      }
    
    }
    
    request.onerror = function(event) {
      console.log("使用游标   keyrange 查询失败")
    }
    

    }

    // 使用索引
    function useIndex() {
    let store = db.transaction('customers').objectStore('customers'),
    index = store.index('name');
    request = index.openCursor();
    request.onsuccess = function (event) {
    let cursor = event.target.result;
    if (cursor) {
    console.log(cursor);
    cursor.continue();
    }
    }
    }

    addBtn.addEventListener('click', function(e) {
    save();
    }, false);

    deleteBtn.addEventListener('click', function(e) {
    deleteData();
    }, false);

    queryBtn.addEventListener('click', function(e) {
    getData();
    }, false);

    cursorBtn.addEventListener('click', function(e) {
    cursorQuery();
    }, false);

    clearBtn.addEventListener('click', function(e) {
    clear();
    }, false);

    keyRange.addEventListener('click', function(e) {
    keyRangeQuery();
    }),

    indexBtn.addEventListener('click', function(e) {
    useIndex();
    })

    </script>

    </body>
    </html>

    示例

    在这个例子中,我们用一个音乐专辑应用作为示范。不过我并不打算在这里从头到尾展示整个应用,而是把涉及IndexedDB的部分挑出来解释。如果大家对这个Web应用感兴趣的话,文章的后面也提供了源代码的下载。首先,让我们来打开数据库并创建store:

    JavaScript

    // check if the indexedDB is supported if (!window.indexedDB) { throw 'IndexedDB is not supported!'; // of course replace that with some user-friendly notification } // variable which will hold the database connection var db; // open the database // first argument is database's name, second is it's version (I will talk about versions in a while) var request = indexedDB.open('album', 1); request.onerror = function (e) { console.log(e); }; // this will fire when the version of the database changes request.onupgradeneeded = function (e) { // e.target.result holds the connection to database db = e.target.result; // create a store to hold the data // first argument is the store's name, second is for options // here we specify the field that will serve as the key and also enable the automatic generation of keys with autoIncrement var objectStore = db.createObjectStore('cds', { keyPath: 'id', autoIncrement: true }); // create an index to search cds by title // first argument is the index's name, second is the field in the value // in the last argument we specify other options, here we only state that the index is unique, because there can be only one album with specific title objectStore.createIndex('title', 'title', { unique: true }); // create an index to search cds by band // this one is not unique, since one band can have several albums objectStore.createIndex('band', 'band', { unique: false }); };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // check if the indexedDB is supported
    if (!window.indexedDB) {
        throw 'IndexedDB is not supported!'; // of course replace that with some user-friendly notification
    }
     
    // variable which will hold the database connection
    var db;
     
    // open the database
    // first argument is database's name, second is it's version (I will talk about versions in a while)
    var request = indexedDB.open('album', 1);
     
    request.onerror = function (e) {
        console.log(e);
    };
     
    // this will fire when the version of the database changes
    request.onupgradeneeded = function (e) {
        // e.target.result holds the connection to database
        db = e.target.result;
     
        // create a store to hold the data
        // first argument is the store's name, second is for options
        // here we specify the field that will serve as the key and also enable the automatic generation of keys with autoIncrement
        var objectStore = db.createObjectStore('cds', { keyPath: 'id', autoIncrement: true });
     
        // create an index to search cds by title
        // first argument is the index's name, second is the field in the value
        // in the last argument we specify other options, here we only state that the index is unique, because there can be only one album with specific title
        objectStore.createIndex('title', 'title', { unique: true });
     
        // create an index to search cds by band
        // this one is not unique, since one band can have several albums
        objectStore.createIndex('band', 'band', { unique: false });
    };

    相信上面的代码还是相当通俗易懂的。估计你也注意到上述代码中打开数据库时会传入一个版本号,还用到了onupgradeneeded事件。当你以较新的版本打开数据库时就会触发这个事件。如果相应版本的数据库尚不存在,则会触发事件,随后我们就会创建所需的store。接下来我们还创建了两个索引,一个用于标题搜索,一个用于乐队搜索。现在让我们再来看看如何增加和删除专辑:

    JavaScript

    // adding $('#add-album').on('click', function () { // create the transaction // first argument is a list of stores that will be used, second specifies the flag // since we want to add something we need write access, so we use readwrite flag var transaction = db.transaction([ 'cds' ], 'readwrite'); transaction.onerror = function (e) { console.log(e); }; var value = { ... }; // read from DOM // add the album to the store var request = transaction.objectStore('cds').add(value); request.onsuccess = function (e) { // add the album to the UI, e.target.result is a key of the item that was added }; }); // removing $('.remove-album').on('click', function () { var transaction = db.transaction([ 'cds' ], 'readwrite'); var request = transaction.objectStore('cds').delete(/* some id got from DOM, converted to integer */); request.onsuccess = function () { // remove the album from UI } });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // adding
    $('#add-album').on('click', function () {
        // create the transaction
        // first argument is a list of stores that will be used, second specifies the flag
        // since we want to add something we need write access, so we use readwrite flag
        var transaction = db.transaction([ 'cds' ], 'readwrite');
        transaction.onerror = function (e) {
            console.log(e);
        };
        var value = { ... }; // read from DOM
        // add the album to the store
        var request = transaction.objectStore('cds').add(value);
        request.onsuccess = function (e) {
            // add the album to the UI, e.target.result is a key of the item that was added
        };
    });
     
    // removing
    $('.remove-album').on('click', function () {
        var transaction = db.transaction([ 'cds' ], 'readwrite');
        var request = transaction.objectStore('cds').delete(/* some id got from DOM, converted to integer */);
        request.onsuccess = function () {
            // remove the album from UI
        }
    });

    是不是看起来直接明了?这里对数据库所有的操作都基于事务的,只有这样才能保证数据的一致性。现在最后要做的就是展示音乐专辑:

    JavaScript

    request.onsuccess = function (e) { if (!db) db = e.target.result; var transaction = db.transaction([ 'cds' ]); // no flag since we are only reading var store = transaction.objectStore('cds'); // open a cursor, which will get all the items from database store.openCursor().onsuccess = function (e) { var cursor = e.target.result; if (cursor) { var value = cursor.value; $('#albums-list tbody').append(' ' value.title '' value.band '' value.genre '' value.year '

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    request.onsuccess = function (e) {
        if (!db) db = e.target.result;
     
        var transaction = db.transaction([ 'cds' ]); // no flag since we are only reading
        var store = transaction.objectStore('cds');
        // open a cursor, which will get all the items from database
        store.openCursor().onsuccess = function (e) {
            var cursor = e.target.result;
            if (cursor) {
                var value = cursor.value;
                $('#albums-list tbody').append('
    ' value.title '' value.band '' value.genre '' value.year '

    ‘); // move to the next item in the cursor cursor.continue(); } }; }

    这也不是十分复杂。可以看见,通过使用IndexedDB,可以很轻松的保存复杂对象,也可以通过索引来检索想要的内容:

    JavaScript

    function getAlbumByBand(band) { var transaction = db.transaction([ 'cds' ]); var store = transaction.objectStore('cds'); var index = store.index('band'); // open a cursor to get only albums with specified band // notice the argument passed to openCursor() index.openCursor(IDBKeyRange.only(band)).onsuccess = function (e) { var cursor = e.target.result; if (cursor) { // render the album // move to the next item in the cursor cursor.continue(); } }); }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function getAlbumByBand(band) {
        var transaction = db.transaction([ 'cds' ]);
        var store = transaction.objectStore('cds');
        var index = store.index('band');
        // open a cursor to get only albums with specified band
        // notice the argument passed to openCursor()
        index.openCursor(IDBKeyRange.only(band)).onsuccess = function (e) {
            var cursor = e.target.result;
            if (cursor) {
                // render the album
                // move to the next item in the cursor
                cursor.continue();
            }
        });
    }

    使用索引的时候和使用store一样,也能通过游标(cursor)来遍历。由于同一个索引值名下可能有好几条数据(如果索引不是unique的话),所以这里我们需要用到IDBKeyRange。它能根据指定的函数对结果集进行过滤。这里,我们只想根据指定的乐队进行检索,所以我们用到了only()函数。也能使用其它类似于lowerBound()upperBound()bound()等函数,它们的功能也是不言自明的。

    六、使用游标

    得到一个可以操作游标的请求对象有两个方法:

    • openCursor(keyRange, direction)
    • openKeyCursor(keyRange, direction)
      这两个方法接收的参数一样, 两个参数都是可选的: 第一个参数是限制值得范围,第二个参数是指定游标方向

    游标的使用有以下几处:

    • 在对象存储空间上使用: var cursor = objectStore.openCursor()
    • 在索引对象上使用: var cursor = index.openCursor()

    总结

    可以看见,在Web应用中使用离线数据并不是十分复杂。希望通过阅读这篇文章,各位能够在Web应用中加入离线数据的功能,使得你们的应用更加友好易用。你可以在这里下载所有的源码,尝试一下,或者修修改改,或者用在你们的应用中。

    赞 收藏 评论

    在对象存储空间上使用游标

    使用游标常见的一种模式是获取对象存储空间上的所有数据.

    var list = []; var objectStore = db.transaction('movies').objectStore('movies'); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { console.log('cursor:', cursor); list.push(cursor.value); cursor.continue(); } else { console.log('Get all data:', list); } };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var list = [];
    var objectStore = db.transaction('movies').objectStore('movies');
    objectStore.openCursor().onsuccess = function(event) {
        var cursor = event.target.result;
        if (cursor) {
            console.log('cursor:', cursor);
            list.push(cursor.value);
            cursor.continue();
        } else {
            console.log('Get all data:', list);
        }
    };

    图片 7

    使用游标时,需要在成功回调里拿到result对象,判断是否取完了数据:若数据已取完,resultundefined; 若未取完,则result是个IDBCursorWithValue对象,需调用continue()方法继续取数据。 也可以根据自己需求, 对数据进行过滤。

    indexedDB2规范中,在对象存储空间对象上纳入了一个getAll()方法,可以获取所有对象:

    objectStore.getAll().onsuccess = function(event) { console.log('result:', event.target.result); };

    1
    2
    3
    objectStore.getAll().onsuccess = function(event) {
        console.log('result:', event.target.result);
    };

    关于作者:njuyz

    图片 8

    (新浪微博:@njuyz) 个人主页 · 我的文章 · 11

    在索引上使用游标

    接着本文上述使用索引的例子,在索引title上使用openCursor()方法时,若不传参数,则会遍历所有数据,在成功回调中的到的result对象有以下属性:

    • key 数据库中这条对象的title属性值
    • primaryKey 数据库中这条对象的alt
    • value 数据库中这条对象
    • direction openCursor()方法传入的第二个对象,默认值为next
    • source IDBIndex对象 举例如下:
    var index = db .transaction('movies')
    .objectStore('movies').index('title'); index.openCursor().onsuccess
    = function(event) { var cursor = event.target.result; if (cursor) {
    console.log('cursor:', cursor); cursor.continue(); } };
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f37afae763506229096-1">
    1
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f37afae763506229096-2">
    2
    </div>
    <div class="crayon-num" data-line="crayon-5b8f37afae763506229096-3">
    3
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f37afae763506229096-4">
    4
    </div>
    <div class="crayon-num" data-line="crayon-5b8f37afae763506229096-5">
    5
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f37afae763506229096-6">
    6
    </div>
    <div class="crayon-num" data-line="crayon-5b8f37afae763506229096-7">
    7
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f37afae763506229096-8">
    8
    </div>
    <div class="crayon-num" data-line="crayon-5b8f37afae763506229096-9">
    9
    </div>
    <div class="crayon-num crayon-striped-num" data-line="crayon-5b8f37afae763506229096-10">
    10
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f37afae763506229096-1" class="crayon-line">
    var index = db
    </div>
    <div id="crayon-5b8f37afae763506229096-2" class="crayon-line crayon-striped-line">
    .transaction('movies')
    </div>
    <div id="crayon-5b8f37afae763506229096-3" class="crayon-line">
    .objectStore('movies').index('title');
    </div>
    <div id="crayon-5b8f37afae763506229096-4" class="crayon-line crayon-striped-line">
    index.openCursor().onsuccess = function(event) {
    </div>
    <div id="crayon-5b8f37afae763506229096-5" class="crayon-line">
      var cursor = event.target.result;
    </div>
    <div id="crayon-5b8f37afae763506229096-6" class="crayon-line crayon-striped-line">
      if (cursor) {
    </div>
    <div id="crayon-5b8f37afae763506229096-7" class="crayon-line">
          console.log('cursor:', cursor);
    </div>
    <div id="crayon-5b8f37afae763506229096-8" class="crayon-line crayon-striped-line">
          cursor.continue();
    </div>
    <div id="crayon-5b8f37afae763506229096-9" class="crayon-line">
      }
    </div>
    <div id="crayon-5b8f37afae763506229096-10" class="crayon-line crayon-striped-line">
    };
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    
    [![](http://jbcdn2.b0.upaiyun.com/2017/12/5451a2dedd05d9226415141022934c72.png)](http://jbcdn2.b0.upaiyun.com/2017/12/5451a2dedd05d9226415141022934c72.png)
    

    在索引title上使用openKeyCursor()方法,若不传参数,同样也会遍历所有数据,result对象属性如下:

    • key 数据库中这条对象的title属性值
    • primaryKey 数据库中这条对象的alt
    • direction openCursor()方法传入的第二个对象,默认值为next
    • source altBIndex对象

    openCursor()方法相比,得到的数据少一个value属性,是没有办法得到存储对象的其余部分

    前面说到,我们要根据索引title获取所有title属性值为寻梦环游记的对象,要使用游标,而又不想遍历所有数据,这时就要用到openCursor()的第一个参数: keyRange

    keyRange是限定游标遍历的数据范围,通过IDBKeyRange的一些方法设置该值:

    var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = []; var index = db .transaction('movies') .objectStore('movies').index('title'); index.openCursor(singleKeyRange).onsuccess = function(event) { var cursor = event.target.result; if (cursor) { console.log('cursor.value:', cursor.value); list.push(cursor.value); cursor.continue(); } else { console.log('list:', list); } };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = [];
    var index = db
    .transaction('movies')
    .objectStore('movies').index('title');
    index.openCursor(singleKeyRange).onsuccess = function(event) {
    var cursor = event.target.result;
    if (cursor) {
    console.log('cursor.value:', cursor.value);
    list.push(cursor.value);
    cursor.continue();
    } else {
        console.log('list:', list);
    }
    };

    图片 9

    IDBKeyRange其他一些方法:

    // 匹配所有在 "Bill" 前面的, 包括 "Bill" var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill"); // 匹配所有在 “Bill” 前面的, 但是不需要包括 "Bill" var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true); // 匹配所有在'Donna'后面的, 但是不包括"Donna" var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true); // 匹配所有在"Bill" 和 "Donna" 之间的, 但是不包括 "Donna" var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 匹配所有在 "Bill" 前面的, 包括 "Bill"
    var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");
     
    // 匹配所有在 “Bill” 前面的, 但是不需要包括 "Bill"
    var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);
     
    // 匹配所有在'Donna'后面的, 但是不包括"Donna"
    var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);
     
    // 匹配所有在"Bill" 和 "Donna" 之间的, 但是不包括 "Donna"
    var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);

    更多请参考 MDN|IDBKeyRange

    游标默认遍历方向是按主键从小到大,有时候我们倒序遍历,此时可以给openCursor()方法传递第二个参数: direction: next|nextunique|prev|prevunique

    var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = []; var index = db .transaction('movies') .objectStore('movies').index('title'); index.openCursor(singleKeyRange, 'prev').onsuccess = function(event) { var cursor = event.target.result; if (cursor) { console.log('cursor.value:', cursor.value); list.push(cursor.value); cursor.continue(); } else { console.log('list:', list); } };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = [];
    var index = db
    .transaction('movies')
    .objectStore('movies').index('title');
    index.openCursor(singleKeyRange, 'prev').onsuccess = function(event) {
    var cursor = event.target.result;
    if (cursor) {
    console.log('cursor.value:', cursor.value);
    list.push(cursor.value);
    cursor.continue();
    } else {
        console.log('list:', list);
    }
    };

    传了prev的结果是按倒序遍历的.

    因为 “name” 索引不是唯一的,那就有可能存在具有相同 name 的多条记录。 要注意的是这种情况不可能发生在对象存储空间上,因为键必须永远是唯一的。 如果你想要在游标在索引迭代过程中过滤出重复的,你可以传递 nextunique(或prevunique, 如果你正在向后寻找)作为方向参数。 当 nextunique 或是 prevunique 被使用时,被返回的那个总是键最小的记录。

    var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = []; var index = db .transaction('movies') .objectStore('movies').index('title'); index.openCursor(singleKeyRange, 'prevunique').onsuccess = function(event) { var cursor = event.target.result; if (cursor) { console.log('cursor.value:', cursor.value); list.push(cursor.value); cursor.continue(); } else { console.log('list:', list); } };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = [];
    var index = db
    .transaction('movies')
    .objectStore('movies').index('title');
    index.openCursor(singleKeyRange, 'prevunique').onsuccess = function(event) {
    var cursor = event.target.result;
    if (cursor) {
    console.log('cursor.value:', cursor.value);
    list.push(cursor.value);
    cursor.continue();
    } else {
        console.log('list:', list);
    }
    };

    图片 10

    七、关闭和删除数据库

    • 关闭数据库只需要在数据库对象db上调用close()方法即可
    db.close();
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f37afae779476637224-1">
    1
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f37afae779476637224-1" class="crayon-line">
    db.close();
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    
    
    关闭数据库后,`db`对象仍然保存着该数据库的相关信息,只是无法再开启事务(调用开启事务方法会报错,提示数据库连接已断开):
    

    图片 11

    • 删除数据库则需要使用indexedDB.deleteDatabase(dbName)方法
    JavaScript
    
    window.indexedDB.deleteDatabase(dbName);
    
    <table>
    <colgroup>
    <col style="width: 50%" />
    <col style="width: 50%" />
    </colgroup>
    <tbody>
    <tr class="odd">
    <td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
    <div class="crayon-num" data-line="crayon-5b8f37afae77e452573671-1">
    1
    </div>
    </div></td>
    <td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
    <div id="crayon-5b8f37afae77e452573671-1" class="crayon-line">
    window.indexedDB.deleteDatabase(dbName);
    </div>
    </div></td>
    </tr>
    </tbody>
    </table>
    

    八、indexedDB的局限性

    以下情况不适合使用IndexedDB

    • 全球多种语言混合存储。国际化支持不好。需要自己处理。
    • 和服务器端数据库同步。你得自己写同步代码。
    • 全文搜索。

    注意,在以下情况下,数据库可能被清除:

    • 用户请求清除数据。
    • 浏览器处于隐私模式。最后退出浏览器的时候,数据会被清除。
    • 硬盘等存储设备的容量到限。
    • 不正确的
    • 不完整的改变.

    总结

    1. 使用indexedDB.open(dbName, version)打开一个数据库连接
    2. 使用indexedDB.deleteDatabase(dbName)删除一个数据库
    3. 在数据库对象db上使用createObjectStore(storeName, config)创建对象存储空间
    4. 在对象存储空间objectStore上使用createIndex(indexName, keyName, config)创建索引
    5. 对数据库的操作都需要通过事务完成: var transction = db.transaction([storeName], mode)
    6. 数据库的增删改查均通过objectStore对象完成,var objectStore = transaction.objectStore(storeName)
    7. 对数据库数据操作有: add()get()delete()put基本使用,Web应用中的离线数据存储。等方法
    8. 查找数据可以使用索引: objectStore.index(indexName)
    9. 遍历和过滤数据可以使用游标: openCursor(keyRange, direction)

    参考链接

    • IndexedDB的基本概念-MDN
    • 使用 IndexedDB-MDN
    • IndexedDB API接口-MDN
    • Indexed Database API 2.0 – w3c

      1 赞 2 收藏 1 评论

    图片 12

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:基本使用,Web应用中的离线数据存储

    关键词:

上一篇:离线网页应用,入门教程

下一篇:没有了