2024-11-04 05:07:52
在HTML5之前,应用程序数据只能存储在cookie中,并且会包含在每个服务器请求中。与cookie不同,浏览器本地存储限制要大得多(至少5MB),并且信息不会被传输到服务器。本文将要介绍的本地存储包括:localStorage、WebSQLDatabase、IndexedDB。
localStoragelocalStorage在一般浏览器支持的是5M大小,在不同的浏览器中localStorage会有所不同。
localstorage的API有两个:localStorage和sessionStorage,存在于window对象中:localStorage对应window.localStorage,sessionStorage对应window.sessionStorage。
localStorage和sessionStorage的区别主要是在于其生存期,localStorage属于永久性存储,而sessionStorage当会话结束的时候,sessionStorage中的键值对会被清空。
localstorage为标准的键值对(Key-Value,简称KV)数据类型,简单也易扩展,只要以某种编码方式把想要存储进localstorage的对象给转化成字符串,就能轻松支持。
由于浏览器的安全策略,localstorage是无法跨域的,也无法让子域名继承父域名的localstorage数据。
在使用方面,sessionStorage和localStorage方法是一样的。
初始化在浏览器中使用需要判断兼容性,判断浏览器是否支持。
if(!window.localStorage){alert("浏览器支持localstorage");returnfalse;}数据存储操作数据写入的方法就是直接给window.localStorage添加一个属性,例如:window.localStorage.a或者window.localStorage["b"]。它的读取、写、删除操作方法很简单,是以键值对的方式存在的,如下:
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");运行后再开发工具下可以看到:
写入数据推荐使用setItem(),读取数据推荐使用getItem(),清除键值对使用removeItem()。如果希望一次性清除所有的键值对,可以使用clear()。另外,HTML5还提供了一个key()方法,可以在不知道有哪些键值的时候使用,如下:
conststorage=window.localStorage;functionshowStorage(){for(vari=0;i<storage.length;i++){//key(i)获得相应的键,再用getItem()方法获得对应的值console.log(storage.key(i)+":"+storage.getItem(storage.key(i))+"<br>");}}需要注意的是,HTML5本地存储只能存字符串,任何格式存储的时候都会被自动转为字符串,所以读取的时候,需要自己进行类型的转换。
对于json数据侧存储需要调用JSON.stringify()将其转为字符串后才能存储,读取出来后调用JSON.parse()将字符串转为json格式。
storage事件事件可以对键值对的改变进行监听,使用方法如下:
if(window.addEventListener){window.addEventListener("storage",handle_storage,false);}elseif(window.attachEvent){window.attachEvent("onstorage",handle_storage);}functionhandle_storage(e){if(!e){e=window.event;}//逻辑}对于事件变量e,是一个StorageEvent对象,提供了一些实用的属性,可以很好的观察键值对的变化,如下表:
PropertyTypeDescriptiontargetEventTarget事件目标(DOM树中的最大目标)typeDOMString事件的类型bubblesBoolean事件通常是否会出现泡沫cancelableBoolean事件是否可取消keyDOMString(string)键更改时oldValueDOMString(string)正在更改键的旧值newValueDOMString(string)正在更改键的新值urlDOMString(string)键更改的文档的地址storageAreaStorage受影响的存储对象WebSQLDatabaseWebSQLDatabase实际上已经被废弃
虽然Html5已经提供了功能强大的localStorage和sessionStorage,但是他们两个都只能提供存储简单数据结构的数据,对于复杂的Web应用的数据却无能为力。逆天的是Html5提供了一个浏览器端的数据库支持,允许直接通JavaScript的API在浏览器端创建一个本地的数据库,而且支持标准的SQL的CRUD操作,让离线的Web应用更加方便的存储结构化的数据。接下里介绍一下本地数据的相关API和用法。
第一步:openDatabase方法:创建一个访问数据库的对象。
第二步:使用第一步创建的数据库访问对象来执行transaction方法,通过此方法可以设置一个开启事务成功的事件响应方法,在事件响应方法中可以执行SQL.
第三步:通过executeSql方法执行查询,当然查询可以是:CRUD。
openDatabase方法初次调用时创建数据库,以后就是建立连接了。
//Demo:获取或者创建一个数据库,如果数据库不存在那么创建之constdataBase=openDatabase("student","1.0","学生表",1024*1024,function(){});openDatabase方法打开一个已经存在的数据库,如果数据库不存在,它还可以创建数据库。几个参数意义分别是:
数据库名称。
数据库的版本号,目前来说传个1.0就可以了,当然可以不填;
对数据库的描述。
设置分配的数据库的大小(单位是kb)。
回调函数(可省略)。
db.transaction方法可以设置一个回调函数,此函数可以接受一个参数就是我们开启的事务的对象。然后通过此对象可以进行执行Sql脚本,跟下面的步骤可以结合起来。
通过executeSql方法执行查询ts.executeSql(sqlQuery,[value1,value2..],dataHandler,errorHandler)参数说明:
qlQuery:需要具体执行的sql语句,可以是create、select、update、delete;
[value1,value2..]:sql语句中所有使用到的参数的数组,在executeSql方法中,将s>语句中所要使用的参数先用“?”代替,然后依次将这些参数组成数组放在第二个参数中
dataHandler:执行成功是调用的回调函数,通过该函数可以获得查询结果集;
errorHandler:执行失败时调用的回调函数;
IndexedDBWebStorage(LocalStorage和SessionStorage)与IndexedDB。WebStorage使用简单字符串键值对在本地存储数据,方便灵活,但是对于大量结构化数据存储力不从心,IndexedDB是为了能够在客户端存储大量的结构化数据,并且使用索引高效检索的API。
异步API在IndexedDB大部分操作并不是我们常用的调用方法,返回结果的模式,而是请求——响应的模式,比如打开数据库的操作
constrequest=window.indexedDB.open('testDB');这条指令并不会返回一个DB对象的句柄,我们得到的是一个IDBOpenDBRequest对象,而我们希望得到的DB对象在其result属性中
这条指令请求的响应是一个IDBDatabase对象,这就是IndexedDB对象
除了result,IDBOpenDBRequest接口定义了几个重要属性
onerror:请求失败的回调函数句柄
onsuccess:请求成功的回调函数句柄
onupgradeneeded:请求数据库版本变化句柄
所谓异步API是指并不是这条指令执行完毕,我们就可以使用request.result来获取indexedDB对象了,就像使用ajax一样,语句执行完并不代表已经获取到了对象,所以我们一般在其回调函数中处理。
创建数据库刚才的语句已经展示了如何打开一个indexedDB数据库,调用indexedDB.open方法就可以创建或者打开一个indexedDB。看一个完整的处理
functionopenDB(name){constrequest=window.indexedDB.open(name);request.onerror=function(e){console.log("OPenError!");};request.onsuccess=function(e){myDB.db=e.target.result;};}constmyDB={name:"test",version:1,db:null,};openDB(myDB.name);代码中定义了一个myDB对象,在创建indexedDBrequest的成功毁掉函数中,把request获取的DB对象赋值给了myDB的db属性,这样就可以使用myDB.db来访问创建的indexedDB了。
version我们注意到除了onerror和onsuccess,IDBOpenDBRequest还有一个类似回调函数句柄——onupgradeneeded。这个句柄在我们请求打开的数据库的版本号和已经存在的数据库版本号不一致的时候调用。
indexedDB.open()方法还有第二个可选参数,数据库版本号,数据库创建的时候默认版本号为1,当传入的版本号和数据库当前版本号不一致的时候onupgradeneeded就会被调用,当然不能试图打开比当前数据库版本低的version,否则调用的就是onerror了,修改一下刚才例子
functionopenDB(name,version){constversion=version||1;constrequest=window.indexedDB.open(name,version);request.onerror=function(e){console.log(e.currentTarget.error.message);};request.onsuccess=function(e){myDB.db=e.target.result;};request.onupgradeneeded=function(e){console.log('DBversionchangedto'+version);};}constmyDB={name:'test',version:3,db:null};openDB(myDB.name,myDB.version);由于刚才已经创建了版本为1的数据库,打开版本为3的时候,会在控制台输出:DBversionchangedto3
关闭与删除数据库关闭数据库可以直接调用数据库对象的close方法
functioncloseDB(db){db.close();}删除数据库使用indexedDB对象的deleteDatabase方法
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");0简单调用
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");1由于异步API愿意,不能保证能够在closeDB方法调用前获取db对象(实际上获取db对象也比执行一条语句慢得多),所以用了setTimeout延迟了一下。当然我们注意到每个indexedDB实例都有onclose回调函数句柄,用以数据库关闭的时候处理。
objectstore有了数据库后我们自然希望创建一个表用来存储数据,但indexedDB中没有表的概念,而是objectStore,一个数据库中可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存储的每条数据和一个键相关联。
可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。选择键的类型不同,objectStore可以存储的数据结构也有差异
键类型存储数据不使用任意值,但是每添加一条数据的时候需要指定键参数keyPathJavascript对象,对象必须有一属性作为键值keyGenerator任意值都使用JavaScript对象,如果对象中有keyPath指定的属性则不生成新的键值,如果没有自动生成递增键值,填充keyPath指定属性事务在对新数据库做任何事情之前,需要开始一个事务。事务中需要指定该事务跨越哪些objectstore。
事务具有三种模式
只读:read,不能修改数据库数据,可以并发执行
读写:readwrite,可以进行读写操作
版本变更:verionchange
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");2给objectstore添加数据调用数据库实例的createObjectStore方法可以创建objectstore,方法有两个参数:storename和键类型。调用store的add方法添加数据。有了上面知识,可以向objectstore内添加数据了
keyPath因为对新数据的操作都需要在transaction中进行,而transaction又要求指定objectstore,所以只能在创建数据库的时候初始化objectstore以供后面使用,这正是onupgradeneeded的一个重要作用,修改一下之前代码
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");3这样在创建数据库的时候就为其添加了一个名为students的objectstore,准备一些数据以供添加
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");4conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");5这样就在studentsobjectstore里添加了三条记录,以id为键,在chrome控制台看看效果
可以调用objectstore的get方法通过键获取数据,以使用keyPath做键为例:
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");7更新数据可以调用objectstore的put方法更新数据,会自动替换键值相同的记录,达到更新目的,没有相同的则添加,以使用keyPath做键为例
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");8删除数据及objectstore调用objectstore的delete方法根据键值删除记录
conststorage=window.localStorage;//写入a字段storage["a"]=1;//写入b字段storage.b=1;//写入c字段storage.setItem("c",3);console.log(typeofstorage["a"]);console.log(typeofstorage["b"]);console.log(typeofstorage["c"]);storage.getItem("a");9调用objectstore的clear方法可以清空objectstore
conststo