离线应用与客户端存储(cookie storage indexedDB)

离线检测

HTML5定义一个属性:navigator.onLine的属性。这个属性值为true,表示设备在线,值为false,表示设备离线。为了更好的确定网络是否可用,HTML5还定义了两个事件。这两个事件是在window对象上触发:online和offline。代码如下:

应用缓存:

HTML5的应用缓存:appcache,专门为开发离线web应用而设计的。appcache就是从浏览器的缓存中分出来的一块缓存区。要想在这个缓存区中保存数据,可以使用一个描述文件(manifest file),列出要下载和缓存的资源。

要将描述文件与页面关联起来,可以在<html>中的manifest属性中指定这个文件路径:

    <html lang="en" manifest="/offline.manifest">

这个文件的MIME类型必须是text/cache-manifest

描述文件的扩展名以前推荐用manifest,现在推荐用appcache。

这个主要的API是applicationCache对象。

这个对象有一个status属性,属性的值是常量,表示应用缓存的如下状态:

0:无缓存,即没有与页面相关的应用缓存。

1:闲置,即应用缓存未得到更新

2:检查中,即应用缓存正在下载描述文件中指定的资源

3:下载中,即应用缓存正在下载描述文件中指定的资源

4:更新完成,即应用缓存已经更新资源,而且所有的资源都已经全部下载完毕。可以通过swapCache()来使用。

5:废弃:即应用缓存的描述文件已经不存在了。因此页面无法再访问应用缓存。

应用缓存还有很多相关的事件,表示其状态的改变,以下就是这些事件:

checking:在浏览器为应用缓存查找更新时触发。

error:在检查更新或者下载资源的期间发生错误时触发

noupdate:在检查描述文件发现文件无变化时触发。

downloading:再开始下载应用缓存资源时触发

progress:在文件下载应用缓存过程中持续不断的触发。

updateready:在页面新的应用缓存下载完毕并且可以通过swapCache()使用时触发。

cached:在应用缓存完整可用时触发。

可以手动干预,让应用缓存检查更新:

    applicationCache.update();

上述事件会依次执行

如果触发了updateready事件,则说明新版本的应用缓存已经可用,而此时需要调用swapCache()来启用新应用缓存。

      applicationCache.onupdateready=function(){
            applicationCache.swapCache();
      }

 数据存储

1、cookie——HTTP coolie,客户端存储会话信息的。该标准要求服务器对任意的HTTP请求发送Set-Cookie HTTP头作为响应的一部分

    /* 
      HTTP/1.1 200 OK
      Content-type: text/html
      Set-Cookie: name=value; expire=expiration_time; path=domain_path; secure
      Other-header: other-header-value
      这个HTTP响应设置以name为名称,以value为值的一个cookie,名称和值在传送时都必须时URL编码
      */

2. cookie组成:
    1. 名称
    2. 值
    3. 域
    4. 路径
    5. 失效时间
    6. 安全标志:cookie只有在使用SSL连接时才发送到服务器

   所有的值和名字都经过URL编码,必须使用decodeURIComponent()解析

   基本的cookie操作:读取,写入和删除

      var CookieUtil={
            get:function(name){
                  var cookieName=encodeURIComponent(name)+"=",
                      cookieStart=document.cookie.indexOf(cookieName),
                      cookieValue=null;
                  if(cookieStart>-1){
                        var 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){
                  var 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;
            },
            unset:function(name,path,domain,secure){
                  this.set(name,"",new Date(0),path,domain,secure);
            }
      }

使用:

      document.cookie="b=a";
      //设置cookie
      CookieUtil.set("name","Nicholas");
      CookieUtil.set("book","Professional JavaScript");
      //读取cookie的值
      console.log(CookieUtil.get("name"));
      console.log(CookieUtil.get("book"));
      //删除cookie
      CookieUtil.unset("b");
      CookieUtil.unset("name");
      CookieUtil.unset("book");
      // 设置cookie,包括它的路径、域、失效时间
      CookieUtil.set("name","bob","/books/projs","www.wrox.com",new Date("January 1,2020"))
      // 删除刚刚设置的cookie
      CookieUtil.unset("name","/books/projs","www.wrox.com");
      // 设置安全的cookie
     CookieUtil.set("hh","bob",null,null,null,true);

2、子cookie

为了绕开浏览器单域名下的cookie数量限制,一些开发人员使用了一种称为子cookie(subcookie)的概念。子cookie是存放在单个cookie中的更小段的数据。也就是使用cookie值来存储多个名值对儿,子cookie最常见的格式如下:

    name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5;

子cookie一般也以查询字符串的格式进行格式化,然后这些值可以使用单个cookie进行存储和访问,而非对每个 名-值对儿使用不同的cookie存储。最后网站或者web应用程序可以无需达到单域名cookie上限也可以存储更加结构化的数据;

为了更好的操作子cookie,必须建立一系列新方法,子cookie的解析和序列化会因为子cookie的期望用途而略有不同并更加复杂些。例如要获得一个子cookie,首先要遵循与获得cookie一样的基本步骤,但是在解码cookie值之前,需要按如下方法找出子cookie的信息。

       var SubCookieUtil={
            //获取子cookie
            get:function(name,subName){
                  var subCookies=this.getAll(name);
                  if(subCookies){
                        return subCookies[subName];
                  }else{
                        return null;
                  }
            },
            // 获取cookie
            getAll:function(name){
                  var cookieName=encodeURIComponent(name)+"=",
                      cookieStart=document.cookie.indexOf(cookieName),
                      cookieValue=null,
                      cookieEnd,
                      subCookies,
                      i,
                      parts,
                      result={};
                  if(cookieStart>-1){
                        cookieEnd=document.cookie.indexOf(";",cookieStart);
                        if(cookieEnd == -1){
                              cookieEnd=document.cookie.length;
                        }
                        cookieValue=document.cookie.substring(cookieStart+cookieName.length,cookieEnd);
                        if(cookieValue.length>0){
                              subCookies=cookieValue.split("&");
                              for(i=0,len=subCookies.length;i<len;i++){
                                    parts=subCookies[i].split("=");
                                    result[decodeURIComponent(parts[0])]=decodeURIComponent(parts[1]);
                              }
                              return result;
                        }
                  }
                  
                  return null;
            },
            // 设置子cookie
            set:function(name,subName,value,expires,path,domain,secure){
                  var subCookies=this.getAll(name)||{};
                  subCookies[subName]=value;
                  this.setAll(name,subCookies,expires,path,domain,secure);
            },
            // 设置cookie
            setAll:function(name,subCookies,expires,path,domain,secure){
                  var cookieText=encodeURIComponent(name)+"=",
                      subcookieParts=new Array(),
                      subName;
                  for(subName in subCookies){
                        //判断subName存在以及subCookies对象包含这个非继承的属性
                        if(subName.length>0&&subCookies.hasOwnProperty(subName)){
                              subcookieParts.push(encodeURIComponent(subName)+"="+encodeURIComponent(subCookies[subName]));

                        }
                  }
                  if(subcookieParts.length>0){
                        cookieText+=subcookieParts.join("&");
                        if(expires instanceof Date){
                              cookieText+="; expires="+expires.toGMTString();
                        }
                        if(path){
                              cookieText+="; path="+path;
                        }
                        if(domain){
                              cookieText+="; domain="+domain;
                        }
                        if(secure){
                              cookieText+="; secure";
                        }
                  }else{
                        cookieText+="; expires="+(new Date(0)).toDateString();
                  }
                  document.cookie=cookieText;
            },
            // 删除子cookie
            unset:function(name,subName,path,domain,secure){
                  var subcookies=this.getAll(name);//一个对象
                  if(subcookies){
                        delete subcookies[subName];
                        this.setAll(name,subcookies,null,path,domain,secure);
                  }
            },
            // 删除cookie
            unsetAll:function(name,path,domain,secure){
                  this.setAll(name,null,new Date(0),path,domain,secure);
            }
      }

使用:

      // 设置两个子cookie
      SubCookieUtil.set("data","name","Nicholas");
      SubCookieUtil.set("data","book","Profession javascript");
      // 设置全部cookie和失效日期
      SubCookieUtil.setAll("data",{name:"Nicholas",book:"Profession javascript"},new Date("January 1,2020"));
      // 修改名字的值,并修改cookie的失效时间
      SubCookieUtil.set("data","name","Michael",new Date("February 1, 2022"));

      // 获取全部子cookie
      var data=SubCookieUtil.getAll("data");
      console.log(data);//{ name: "Michael", book: "Profession javascript" }
      console.log(data.name);//Michael
      console.log(data.book);//Profession javascript
      // 逐个获取子cookie
      console.log(SubCookieUtil.get("data","name"));//Michael
      console.log(SubCookieUtil.get("data","book"));//Profession javascript

      // 删除子cookie
      SubCookieUtil.unset("data","name");
      // 删除整个cookie
      SubCookieUtil.unsetAll("data");

 3、关于cookie的思考

还有一类cookie被称为,HTTP专有cookie,HTTP专有cookie可以从浏览器或者服务器设置,但是只能从服务器端读取,因为javascript无法获取HTTP专有cookie的值。

由于所有的cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能。cookie信息越大,完成对服务器请求的时间就越长。尽管浏览器对cookie进行了大小限制,不过最好还是尽可能在cookie中少存储信息,以避免影响性能。(一些重要的信息都不能存在cookie中)。

cookie的性质以及局限使得其并不能存储大量的信息,所以又出现了其它方法。

 4、IE用户数据(只支持IE5,以上版本没试过)

在IE5.0中,微软通过一个自定义行为引入了持久化用户数据的概念。用户数据允许每个文档最多128kb,每个域名最多1MB数据。要使用持久化用户数据,首先必须如下所示,使用css在某个元素上指定userData行为:

    <div class="red" id="dataStore" style="behavior:url(#default#userData)"></div>

一旦使用userData行为,那么久可以使用setAttribute()方法,在上面保存数据了。为了将数据提交到浏览器缓存中,还必须调用save()方法并告诉它要保存到数据空间的名字。数据空间名字可以任意定义。仅用于区分不同的数据集。例如:

      var dataStore=document.getElementById("dataStore");
      dataStore.setAttribute("name","Nicholas");
      dataStore.setAttribute("book","Professional Javascript");
      dataStore.save("BookInfo");//自定义的数据空间名字

以上代码中,div元素上存入了两部分信息。在用setAttribute()存储了数据之后,调用了save()方法,指定了数据空间的名称为BookInfo。下一次页面载入之后,可以使用load()方法指定同样的数据空间名称来获取数据,如下所示:

      dataStore.load("BookInfo");

调用load()方法之后就可以用getAttribute()方法来获取了:

      console.log(dataStore.getAttribute("name"));//Nicholas

还可以用removeAttitude()方法将指定的元素数据删除:

      dataStore.removeAttribute("name");
      dataStore.sava("BookInfo");

 Web Storage

web storage是HTML5的一部分,Web Storage的目的是克服有cookie带来的一些限制,当数据需要被严格控制在客户端时,无需持续的将数据发回服务器。

web storage的两个主要目标是:

1、提供一种在在cookie之外存储会话数据的途径。

2、提供一种存储大量可以跨会话存在的数据机制。

1、Storage类型

Storage类型提供最大的存储空间(因浏览器而异)来存储名值对儿。Storage的实例与其他对象类似,有如下方法:

1.length:唯一的属性,只读,用来获取storage内的键值对数量。

2、key(index):根据index获取storage的键名

3、getItem(name):根据key获取storage内的对应value

4、setItem(name,value):为storage内添加键值对

5、removeItem(name):根据键名,删除键值对

6、clear():清空storage对象

Storage类型只能存储字符串,非字符串的数据在存储之前会被转换成字符串。

2.sessionStorage对象(会话存储)

sessionStorage对象是Storage对象的一个实例,Storage支持的属性和方法,sessionStorage都支持

用法:

      // 设置值
      sessionStorage.setItem("name","Nicholas");
      sessionStorage.setItem("book","Javascript");
      sessionStorage.setItem("age",26);
      sessionStorage.setItem("job","coding");
      // 获取值
      console.log(sessionStorage.getItem("name"));//Nicholas
      console.log(sessionStorage["name"]);//Nicholas
      console.log(sessionStorage.name);//Nicholas
      // 删除某个值
      sessionStorage.removeItem("name");
      delete sessionStorage.name;//这种删除方法不推荐
      // 结合length属性和key方法来迭代sessionStorage中的值
      for(var i=0,len=sessionStorage.length;i<len;i++){
            var key=sessionStorage.key(i);
            var value=sessionStorage.getItem(key);
            console.log(key+"="+value);
      }
      //还可以用for-in循环来迭代(这样把sessionStorage对象上的方法、属性、和存储的值都遍历出来了)
      for(var key in sessionStorage){
            var value=sessionStorage.getItem(key);
            console.log(key+"="+value);
      }
      // 清空会话存储
      sessionStorage.clear();

3.globalStorage对象

globalStorage和localStorage都可以跨会话存储数据;

要使用globalStorage,首先要指定那些域可以访问该数据。可以通过方括号标记使用属性来实现:

      // 保存数据
      globalStorage["www.wrox.com"].name="Nicholas";//只有在www.wrox.com域下才能访问,其它子域不能访问
      // 获取数据
      console.log(globalStorage["www.wrox.com"].getItem("name"));
      console.log(globalStorage["www.wrox.com"].name);
      // globalStorage不是Storage的实例,globalStorage["www.wrox.com"]才是Storage的实例
      globalStorage[""].book="javascript";//任何域都可域都可以访问(有安全问题)
      globalStorage[location.host].age=26;//当前域可访问

4、localStorage(大部分浏览器限制存储空间为2.5MB)

localStorage也是Storage的一个实例,和sessionStorage的区别是,localStorage可跨会话存储,而sessionStorage是会话存储(关闭网页就消失)。

使用方法和sessionStorage一样:

      // 设置值
      localStorage.setItem("name","Nicholas");
      localStorage.setItem("book","Javascript");
      localStorage.setItem("age",26);
      localStorage.setItem("job","coding");
      // 获取值
      console.log(localStorage.getItem("name"));//Nicholas
      console.log(localStorage["name"]);//Nicholas
      console.log(localStorage.name);//Nicholas
      // 删除某个值
      localStorage.removeItem("name");
      delete localStorage.name;//这种删除方法不推荐
      // 结合length属性和key方法来迭代localStorage中的值
      for(var i=0,len=localStorage.length;i<len;i++){
            var key=localStorage.key(i);
            var value=localStorage.getItem(key);
            console.log(key+"="+value);
      }
      //还可以用for-in循环来迭代(这样把localStorage对象上的方法、属性、和存储的值都遍历出来了)
      for(var key in localStorage){
            var value=localStorage.getItem(key);
            console.log(key+"="+value);
      }
      // 清空会话存储
      localStorage.clear();

 indexedDB(数据库)

Indexed Database API,或简称IndexedDB,是在浏览器中保存结构化数据的一种数据库。indexedDB是为了代替目前以废弃的Web SQL Database API而出现的。indexedDB的思想是创建一套API ,方便保存和读取javascript对象,同时还支持查询及搜索。

indexedDB设计的操作完全是异步进行的。因此,大多数操作会以请求的方式进行,但这些操作会在后期执行,然后如果成功则返回结果,如果失败则返回错误。差不多每一次IndexedDB操作都需要你注册onerror或onsuccess事件处理程序,以确保适当的处理结果。

在得到完整支持的情况下,IndexedDB将是一个作为API宿主的全局对象。由于API仍然可能有变化,浏览器也都使用提供商前缀,因此这个对象在IE10中叫msIndexedDB,在firefox4中叫mozIndexedDB,在chrome中叫webkitIndexedDB.所以没一个示例前都应该加上以下代码:

var indexedDB=window.indexedDB||window.msIndexedDB||window.mozIndexedDB||window.webkitIndexedDB;

1.打开数据库

IndexedDB就是一个数据库,与MySQL或Web SQL Database等这些以前可能用过的数据库类似。IndexedDB最大的特色是使用对象保存数据,而不是使用表格保存数据。一个IndexedDB数据库,就是一组位于相同命名空间下的对象集合。

使用indexedDB的第一步是打开它,即要把打开的数据库名传给indexedDB.open()。如果传入的数据库已经存在,就会发送一个打开它的请求;如果传入它的数据库不存在,就会发送一个创建并打开它的请求。总之,调用indexedDB.open()。会返回一个IDBRequest对象,在这个对象上可以添加onerror和onsuccess和onupgradeneeded事件处理程序。

在这两个事件处理程序中,event.target都指向request对象,因此他们可以互换使用。如果响应的是onsuccess事件处理程序,那么event.target.result中将有一个数据库实例对象(IDBDatabase),这个对象会保存在database变量中。如果发生了错误,那event.target.errorCode中将保存一个错误码,表示问题的性质,以下是可能的错误码:

错误码 解释
IDBDatabaseException.UNKNOWN_ERR(1) 以外错误,无法归类
IDBDatabaseException.NON_TRANSIENT_ERR(2) 操作不合法
IDBDatabaseException.NOT_FOUND_ERR(3) 未发现要操作的数据库
IDBDatabaseException.CONSTRAINT_ERR(4) 违反了数据库约束
IDBDatabaseException.DATA_ERR(5) 提供给事务的数据不能满足要求
IDBDatabaseException.NOT_ALLOWED_ERR(6) 操作不合法
IDBDatabaseException.TRANSACTION_INACTIVE_ERR(7) 试图重用以完成的任务
IDBDatabaseException.ABORT_ERR(8) 请求中断,未成功
IDBDatabaseException.READ_ONLY_ERR(9) 试图在只读模式下写入或修改数据
IDBDatabaseException.TIMEOUT_ERR(10) 在有效时间内未完成操作
IDBDatabaseException.QUOTA_ERR(11) 磁盘空间不足
例如:
      var indexedDB= window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
      var IDBRequest =indexedDB.open("admin1","1.0");//返回一个IDBRequest对象
      var db;//拿到数据库实例
      IDBRequest.onerror=function(event){
            console.log("数据库打开失败,错误码:"+event.target.errorCode);
      }
      IDBRequest.onsuccess=function(event){
            console.log("success");
            db=IDBRequest.result;//拿到数据库对象
      }
      IDBRequest.onupgradeneeded=function(event){
            console.log("版本更新");
            db=event.target.result;//拿到数据库实例
      }

2.新建数据库(对象储存空间)

只要对数据库进行改动(增,删,改)都需要创建对象存储空间

创建对象存储空间必须在onupgradeneeded事件处理程序中进行

      IDBRequest.onupgradeneeded=function(event){
            console.log("版本更新");
            db=event.target.result;//拿到数据库实例
            //创建对象存储空间必须在onupgradeneeded事件处理程序中进行
            var objectStore;
            if(!db.objectStoreNames.contains('person')){//判断一下这张"表格"是否存在
                  objectStore = db.createObjectStore('person', { keyPath: 'id' });
            }
      }

主键(key)是默认建立索引的属性。比如,数据记录是{ id: 1, name: '张三' },那么id属性可以作为主键。

主键也可以指定为下一层对象的属性,比如{ foo: { bar: 'baz' } }foo.bar也可以指定为主键。

如果数据记录里面没有合适作为主键的属性,那么可以让 IndexedDB 自动生成主键

    var objectStore = db.createObjectStore('person',{ autoIncrement: true });

3、新建对象仓库以后,下一步可以新建索引

      IDBRequest.onupgradeneeded=function(event){
            console.log("版本更新");
            db=event.target.result;//拿到数据库实例
            //创建对象存储空间必须在onupgradeneeded事件处理程序中进行
            var objectStore;
            if(!db.objectStoreNames.contains('person')){//判断一下这张"表格"是否存在
                  objectStore = db.createObjectStore('person', { keyPath: 'id' });
            }
            objectStore.createIndex('name', 'name', { unique: false });
            objectStore.createIndex('email', 'email', { unique: true });
      }

上面代码中,IDBObject.createIndex()的三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)。

4、新增数据、更改或新增数据、获取数据、删除数据、根据索引获取数据、使用游标查询

 新增数据指的是向对象仓库写入数据记录。这需要通过事务完成。

跨过创建对象存储空间这一步之后,接下来的所有操作都是通过事务来完成的。在数据库对象上调用transaction()方法可以创建事务,任何时候,只要想读取或修改数据,都要通过事务来组织所有操作

      var indexedDB= window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
      var IDBOpenRequest =indexedDB.open("admin2.6","3");
      IDBOpenRequest.onerror=function(event){
            console.log("数据库打开失败,错误信息:"+event.target.error.message);
      }
      IDBOpenRequest.onsuccess=function(event){
            var IDBDatabase;//返回数据库对象
            console.log("success");
            IDBDatabase=IDBOpenRequest.result;//拿到数据库对象
            // 新增数据
            // add(IDBDatabase);
            // 新增或更改数据
            put(IDBDatabase);
            //获取表单数据
            // get(IDBDatabase);
            // 删除表单数据
            // deleteDBvalue(IDBDatabase);
            // 用索引取值
            // useIndexGetValue(IDBDatabase);
            // 游标查询(遍历数据)
            readAll(IDBDatabase);
      }
      IDBOpenRequest.onblocked=function(event){
            console.log("上次的数据库连接还未关闭");
      }
      IDBOpenRequest.onupgradeneeded=function(event){//版本更新才会走着一步
            console.log("版本更新");
            var db;//返回数据库实例
            console.log(event.target.result);
            db=event.target.result;//拿到数据库实例
            //创建对象存储空间必须在onupgradeneeded事件处理程序中进行
            var objectStore;
            if(!db.objectStoreNames.contains('person3')){//判断一下这张"表格"是否存在
                  objectStore = db.createObjectStore('person3', { keyPath: 'id' });
            }else{
                  console.log("对象仓库已存在");
            }
            //可以新建索引
            // 索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。
            // 三个参数代表索引、属性名、数据是否重复
            objectStore.createIndex('name', 'name', { unique: true });
            objectStore.createIndex('email', 'email', { unique: true });
            
      }
      // 在指定的表单中新增数据
      function add(objectStore) {
            //创建事务
            var IDBTransaction  = objectStore.transaction(['person3'], 'readwrite');
            //在表单中添加数据
            var IDBTransactionRequest= IDBTransaction .objectStore('person3')
            .add({ id: 3, name: '张三', age: 26, email: 'zhangsan@example.com' });
            IDBTransactionRequest .onsuccess = function (event) {
                  console.log('数据写入成功');
            };
            IDBTransactionRequest.onerror=function(event){
                  console.log("写入数据失败");
            }

            IDBTransaction .onerror = function (event) {//add()方法天剑已经存在的属性值时会报错,这时应该用put()方法
                  console.log('事务失败');
                  console.log(event.target.error.message);
            }
            IDBTransaction .oncomplete=function(event){//检测版本升级事务是否完成,若完成则再进行添加数据事务
                    console.log("全部事务已完成");
            }
      }
      // 在指定的表单中新增或修改数据也可以用于删除对象仓库中的某一个值
      function put(objectStore){
           //创建事务
           var IDBTransaction  = objectStore.transaction(['person3'], 'readwrite');
            //在表单中添加数据
            var IDBTransactionRequest =IDBTransaction .objectStore('person3')
            .put({ id: 3, name: '李四', age: 20, email: 'zhangsan@example.com',job:"coding"});
            IDBTransactionRequest .onsuccess = function (event) {
                  console.log('数据写入成功');
            };
            IDBTransactionRequest.onerror=function(event){
                  console.log("新增或更改数据失败");
            }

            IDBTransaction .onerror = function (event) {
                  console.log('事务失败');
                  console.log(event.target.error.message);
            }
            IDBTransaction .oncomplete=function(event){//检测版本升级事务是否完成,若完成则再进行添加数据事务
                    console.log("全部事务已完成");
            } 
      }

      function get(objectStore){
            //创建事务
           var IDBTransaction  = objectStore.transaction(['person3'], 'readwrite');
            //在表单中的数据
            var IDBTransactionRequest=IDBTransaction .objectStore('person3')
            .get(1);//参数是主键的值
            IDBTransactionRequest .onsuccess = function (event) {
                  console.log('获取数据成功');
                  console.log(event.target.result);
            };
            IDBTransactionRequest.onerror=function(event){
                  console.log("获取数据失败");
            }

            IDBTransaction .onerror = function (event) {
                  console.log('事务失败');
                  console.log(event.target.error.message);
            }
            IDBTransaction .oncomplete=function(event){//检测版本升级事务是否完成,若完成则再进行添加数据事务
                    console.log("全部事务已完成");
            } 
      }

      // 删除delete
      function deleteDBvalue(objectStore){
            //创建事务
           var IDBTransaction  = objectStore.transaction(['person3'], 'readwrite');
            //在表单中的数据
            var IDBTransactionRequest=IDBTransaction .objectStore('person3')
            .delete(1);//参数是主键的值   另外clear()方法是删除所有对象 不知道有什么区别
            IDBTransactionRequest .onsuccess = function (event) {
                  console.log('删除数据成功');
                  console.log(event.target.result);
            };
            IDBTransactionRequest.onerror=function(event){
                  console.log("删除数据失败");
            }

            IDBTransaction .onerror = function (event) {
                  console.log('事务失败');
                  console.log(event.target.error.message);
            }
            IDBTransaction .oncomplete=function(event){//检测版本升级事务是否完成,若完成则再进行添加数据事务
                    console.log("全部事务已完成");
            } 
      }

      // 使用索引取值
      function useIndexGetValue(objectStore){
            //创建事务
           var IDBTransaction  = objectStore.transaction(['person3'], 'readwrite');
            //在表单中的数据
            console.log(IDBTransaction .objectStore('person3'))
            var IDBTransactionRequest=IDBTransaction .objectStore('person3');
            var index=IDBTransactionRequest.index("name");
            var requst=index.get("李四");
            requst .onsuccess = function (event) {
                  console.log('根据索引获取数据成功');
                  console.log(event.target.result);
            };
            requst.onerror=function(event){
                  console.log("根据索引获取数据失败");
            }

            IDBTransaction .onerror = function (event) {
                  console.log('事务失败');
                  console.log(event.target.error.message);
            }
            IDBTransaction .oncomplete=function(event){//检测版本升级事务是否完成,若完成则再进行添加数据事务
                    console.log("全部事务已完成");
            } 
      }
      
      // 游标查询(遍历仓库对象中的数据)
      function readAll(objectStore){
           //创建事务
           var IDBTransaction  = objectStore.transaction(['person2','person3'], 'readwrite');
           var IDBTransactionRequest=IDBTransaction .objectStore('person2','person3');
            var coursorRequest =IDBTransactionRequest.openCursor();
            coursorRequest.onsuccess=function(event){
                  var cursor=event.target.result;
                  console.log(cursor);
                  if(cursor){
                        console.log("id:"+cursor.key);
                        console.log("name:"+cursor.value.name);
                        console.log("age:"+cursor.value.age);
                        console.log("email:"+cursor.value.email);
                        console.log("job:"+cursor.value.job);
                        // 更新值
                        var value=cursor.value;
                        value.job="挑粪";
                        updateRequest=cursor.update(value);
                        updateRequest.onsuccess=function(){
                              console.log("值更新成功");
                        }
                        updateRequest.onerror=function(){
                              console.log("值更新失败");
                        }
                        cursor.continue();//向下移动一项参数可以是主键(key)
                        console.log("id:"+cursor.key);
                        // cursor.advance(1);//向前移动一项
                  }else{
                        console.log("没有更多数据了");
                  }
            }

            coursorRequest.onerror=function(event){
                  console.log("游标查询失败");
            }
      }

还可以使用键范围来配合游标查询,具体可以查看文档

原文地址:https://www.cnblogs.com/fqh123/p/10639603.html