HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)

一、本地存储

我们经常会使用Cookie来存储键值队数据。但是Cookie本身存在一定的局限性。

Cookie本身的局限性:

  • 存储大小限制,仅4KB左右。
  • 单个域名小的数量限制,50个左右。
  • 污染请求头,浪费流量

所以对浏览器来说,使用 Web Storage 存储键值对比存储 Cookie 方式更好,而且容量更大。
Web Storage(本地存储)包含两种:localStorage 和 sessionStorage。



1.localStorage 和 sessionStorage

在浏览器的开发者工具下的Appliction中可以看到
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第1张图片
就是这两个玩意。

两种存储方式的不同点:

1 .不同的存储时效:localStorage持久储存,除非主动删除数据,否则数据永远不会过期;sessionStorage会话结束(也就是网页关闭、浏览器关闭、或者说只标签页关闭)变会消失,而且存储的数据只能在同一个会话的页面才能访问。
2. 不同的存储容量:localStorage大小一般2-5M,sessionStorage存储大小不一样,一些浏览器不设限。


两种存储方式的相同点:

  1. 使用...Storage.setItem('key','value')设置内容。
  2. 使用...storage.getItem('key')方法获取内容。
  3. 使用...Storage.removeItem('key')方法清除内容。
  4. 使用...Storage.clear()方法清除所有内容。
  5. 使用...Storage.length属性获取长度。
  6. 使用...Storage.key(index)方法获取对应的下标的键值对的键名。

ps:localStorage和sessionStorage拥有相同的API,拥有不同的存储时效和容量



2.使用Storage的注意事项

由于各个浏览器对于Storage都有限制,我们使用的时候要注意一下几点。

2.1 存储容量超出限制

存储容量一旦超出限制,会抛出QuotaExceededError异常

**所以我们存储键值对时应该使用try{ ... }catch(e){ .... }**来捕获异常。

2.2 存储类型的限制

Storage仅能存储字符串,所以在使用.setItem()设置值的时候,浏览器会默认调用对象本身的toString()方法,若没有,再调用浏览器的toString()方法将任何值都转成字符串,再取数据的判断的时候注意类型。

//localStorage和sessionStorage的结果是一样的。
//**************************以下所有返回值都是String类型
localStorage.setItem('k1',false);
localStorage.getItem('k1');  // "false" 

localStorage.setItem('k2',window.undefined);
localStorage.getItem('k2');	 // "undefined"

localStorage.setItem('k3',null);
localStorage.getItem('k3');	 // "null"

localStorage.setItem('k4',0);
localStorage.getItem('k4');	 // "0"

localStorage.setItem('k5','');
localStorage.getItem('k5');	 // ""

//空数组
localStorage.setItem('k6',[]);
localStorage.getItem('k6');  // ""

localStorage.setItem('k7',[1,2,3,4]);
localStorage.getItem('k7');	 // "1,2,3,4"

//空对象
localStorage.setItem('k8',{});
localStorage.getItem('k8');	 // "[object Object]"

localStorage.setItem('k9',{a:1});
localStorage.getItem('k9');	 // "[object Object]"

localStorage.setItem('k10',{toString:function(){ return 'tostringed'; }});
localStorage.getItem('k10'); // "tostringed"

localStorage.setItem('k11',{toString: function(){ return 100;}});
localStorage.getItem('k11'); // "100"

从上面我们可以看出用Storage存储对象的话,会被统一转化成"[object Object]"
如果想使用Storage存储对象,方法如下

localStorage.setItem( 'k12',JSON.stringify({data:123}) );
localStorage.getItem('k12');	// "{"data":123}"
//使用 JSON.parse可以将字符串转换成对象
JSON.parse( localStorage.getItem('k12'); ) // {data:123} | object类型

2.3 sessionStorage的失效机制

  • 刷新页面不会失效
  • 相同URL不同标签页不能共享sessionStorage


3.封装一个带有过期机制的localStorage

功能:

  • 设置数据的存储时间(毫秒)
  • 过期数据清理
  • 自行维护存储容量
	(function(){
		var ls = window.localStorage;

		function oops(){	//浏览器不支持localStorage警告
			return console.warn('your browser is not supported localStorage API');
		}
		function getItem(key){
			var data = ls.getItem(key);
			data  = JSON.parse(data) || {}; //如果数据被情况,data会得到null,这里给他赋个空对象

			if(data.time === 0){	//是持久化数据
				return data.value;
			}else if(Date.now() > data.time){	//数据过期
				return '';
			}else{
				return typeof data.value !== 'undefined'? data.value : '';
			}
		}
		function setItem(key,value,time){
			if(typeof key === 'undefined')return;
			var data = {
				time: time? Date.now() + time : 0,
				value : value
			}
			data = JSON.stringify(data);
			try {
				ls.setItem(key,data);
			} catch(e){
				ls.clear();
				ls.setItem(key,data);
			}
		}
		function removeItem(key){
			ls.removeItem(key);
		}
		function clear(){
			ls.clear();
		}

		window.myStorage = {
			getItem: ls ? getItem : oops,
			setItem: ls ? setItem : oops,
			removeItem: ls ? removeItem : oops,
			clear: ls ? clear : oops
		}
	})()


4.IndexedDB数据库

IndexedDB是HTML5规范里新出现的浏览器里内置的数据库。存储在IndexedDB里的数据是永久保存,不像cookies那样只是临时的。

  • indexedDB数据库是一种事务型数据库
  • 是NoSQL数据库
  • 使用JS对象存储数据
  • 创建的indexedDB数据库只有在同一个域名下才能共用

查看数据库
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第2张图片

4.1 创建(打开)数据库

  • indexedDB.open(name,verson) 创建或连接数据库(name为数据库名称,verson为数据库版本,数据库创建时不指定verson会默认为1)
  • 连接数据库成功后,返回IDBOpenDBRequest对象
  • IDBOpenDBRequest对象有3个重要回调函数
    1. onerror:请求失败的回调函数
    2. onsuccess:请求成功的回调函数
    3. onupgraeneeded:在请求打开数据库的版本号和已经存在数据库版本号不一致的时候调用,不能试图打开比当前数据库版本低的verson,否则调用onerror(创建objectStore时会用到,此回调的触发顺序在onsuccess前)
  • IDBOpenDBRequest对象不是我们希望得到的DB对象,DB对象在result中,IDBOpenRequest.result才是我们要操作数据库的DB对象。
//例子
	var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
	var dbName = 'testDB',
		verson = 1,
		request;

	function openDB(dbName){
		request = indexedDB.open(dbName,verson);
		request.onerror = function(e){
			console.log(e.currentTarget.error.message);
		}
		request.onsuccess = function(){
			db = request.result;
			console.log('success open');
		}
	}

	openDB(dbName);

数据库打开成功返回IDBOpenDBQequest
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第3张图片

由于已经创建了verson为1的数据库,我们再次打开相同数据库,并修改verson为2

	var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
	var dbName = 'testDB',
		verson = 2, //版本号升级了
		request;

	function openDB(dbName){
		request = indexedDB.open(dbName,verson);
		request.onerror = function(e){
			console.log(e.currentTarget.error.message);
		}
		request.onsuccess = function(){
			db = request.result;
			console.log('success open');
		}
		request.onupgradeneeded = function(){
			console.log('DB verson changed to '+verson);
		}
	}

	openDB(dbName);

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第4张图片

当前verson为2,如果修改回,则会报错
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第5张图片


4.2 关闭和删除数据库

4.2.1 关闭数据库

使用 indexedDB.open 连接数据库成功后会返回一个 IDBOpenDBRequest 对象,我们可以调用该对象的 close 方法来关闭数据库。

var request = indexedDB.open('testDB',1);
var db = request.result;
db.close();

4.2.2 删除数据库

indexedDB.deleteDatabase(name); //name为数据库名称
//例子

//....
var obj = indexedDB.deleteDatabase('DB1');
console.log(obj);

删除数据库也会返回一个IDBOpenDBRequest对象
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第6张图片

PS:建议尽量在控制台中删除数据库


4.3 创建"数据表"(objectStore)

  • indexed中没有表的概念,而是objectStore
  • 一个数据库中可以包含多个objectStore
  • 只要创建objectStore,就必须更改版本号(版本号不能比之前低),并在onupgradeneeded回调函数中创建新的objectStore
IDBOpenRequest.result.createObjectStore(osName, keyType); //osName为表名,{autoIncrement: true}设置主键自增

keyType的两种类型

  1. 设置自增主键 {autoIncrement:true}
  2. 取js对中一个属性作为主键 {keyPath: ‘字段名’}

创建objectStore

//例子
	var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
	var dbName = 'testDB',
		verson = 3,
		storeName = 'os1',
		request,
		db;

	function openDB(dbName){
		request = indexedDB.open(dbName,verson);
		request.onerror = function(e){
			console.log(e.currentTarget.error.message);
		}
		request.onsuccess = function(){
			db = request.result;
			console.log('success open');
		}
		request.onupgradeneeded = function(){
			db = request.result;
			if(!db.objectStoreNames.contains('os1')){	//当要创建的表不存在时
				db.createObjectStore('os1',{keyPath: 'id'});
			}
			console.log('DB verson changed to '+verson);
		}
	}
	openDB(dbName);

创建objectStore这个动作必须要放在onupgradeneeded中,如果在onsuccess中创建会报错Failed to execute 'createObjectStore' on 'IDBDatabase'

		request.onsuccess = function(){
			db = request.result;
			if(!db.objectStoreNames.contains('os1')){	//当要创建的表不存在时
				db.createObjectStore('os1',{keyPath: 'id'});
			}
			console.log('success open');
		}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第7张图片


4.4 事务(transaction)

在对数据库做任何事(数据表的增、删、改、查)都需要通过事务。

indexedDB—>transaction—>objectStore


要通过事务操作数据表步骤:
  • 打开一个事务 var transaction = db.transaction(storeName, 'readwrite');
    事务具有三种模式
    1. 只读:read(不能修改数据库,可以并发执行)
    2. 读写:readwrite(能进行读写操作,最常用的)
    3. 版本更变:verionchange
  • 通过事务获取要操作的objectStore var store = transaction.objectStore(storeName); 这样我们就得到了"数据表",也就是IDBObjectStore对象

关于“表”的增删改查
  1. 增加数据 IDBObjectStore.add
  2. 获取数据 IDBObjectStore.get
  3. 获取所有数据 IDBObjectStore.getAll
  4. 更新数据 IDBObjectStore.put
  5. 删除数据 IDBObjectStore.delete
  6. 清除所有数据 IDBObjectStore.clear

PS:add 和 put 的作用类似,区别在于 put 保存数据时,如果该数据的主键在数据库中已经有相同主键的时候,则会修改数据库中对应主键的对象,而使用 add 保存数据,如果该主键已经存在,则保存失败。

以上操作会返回一个 IDBRequest 对象


DBRequest对象中三个常用的方法
  1. IDBRequest.onsuccess=function(){} 绑定完成事件;
  2. IDBRequest.onerror-function(){} 绑定失败事件;
  3. IDBRequest.result 获取查询结果。

4.4.1 增

增加数据IDBObjectStore.add()

//indexed.open()打开数据库部分略
	var data = [
		{
			name: '穆',
			id: 1,
			job: '白羊座黄金圣斗士',
		},
		{
			name: '阿鲁迪巴',
			id: 2,
			job: '金牛座黄金圣斗士',
		},
		{
			name: '撒加',
			id: 3,
			job: '双子座黄金圣斗士',
		},
		{
			name: '迪斯马斯克',
			id: 4,
			job: '巨蟹座黄金圣斗士',
		},
		{
			name: '艾奥里亚',
			id: 5,
			job: '狮子座黄金圣斗士',
		}
		{
			name: '沙加',
			id: 6,
			job: '处女座黄金圣斗士',
		}
	];
	function addData(){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		data.map(function(o){
			store.add(o);
		});
	}

PS:addData()这个操作,只要indexed.open打开数据库后,随便那都可以调用
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第8张图片


4.4.2 查

	function getData(id){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		var request = store.get(id);
		request.onsuccess =function(){
			console.log(request.result);
		}
	}
	function getAllData(){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		var request = store.getAll();
		request.onsuccess = function(){
			console.log(request.result);
		}
	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第9张图片

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第10张图片


4.4.3 改

	function updateData(data){
		if(typeof data !== 'object')return;
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		var request = store.put(data);
			request.onsuccess = function(){
			console.log(request.result);
		}
	}

如果插入的数据的主键不存在,就是添加
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第11张图片

如果添加的数据的主键已存在,就是修改
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第12张图片


4.4.4 删

	function deleteData(id){ //删除指定数据
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		var request = store.delete(id);
		request.onsuccess = function(){
			console.log(request.result);
		}
	}
	
	function deleteAllData(){ //删除所有数据
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		var request = store.clear();
		request.onsuccess = function(){
			console.log(request.result);
		}

	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第13张图片


4.5 索引

使用 IDBObjectStore,get()IDBObjectStore,getAll() 这两个查询方法我们只能根据主键或者搜索全部数据。我们如果需要根据数据中任意一个字段的值来查询数据,这就用到索引了。

索引的意义在于,可以根据任意的字段的值查询数据,从任意的字段拿到数据。

索引中的数据是和objectStore同步的,索引中的数据被修改,objectStore中也一样被修改


4.5.1 创建索引

索引是在创建objectstore的时候创建的。

IDBObjectStore.createIndex(indexName,KeyPath,optionPara);
  • indexName:索引名称(一般就是要做成索引的字段名+Name)
  • keypath:索引字段。可以是数组。
  • optionPara:索引配置参数。可选值如下:
    1. {unique:true | false} 表示keyPath字段的数据是否唯一。(当字段设置为{unique:true},但字段的数据并不具有唯一性,那整个 IDBObjectStore.add() 的操作是失败的,objectStore中会没有数据
    2. {multiEntry:true} 表示为keyPath字段的每一项建立一条索引数据

例子
	var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
	var dbName = 'testDB',
		verson = 1,
		storeName = 'os1',
		request,
		db;

	function openDB(dbName){
		request = indexedDB.open(dbName,verson);
		request.onerror = function(e){
			console.log(e.currentTarget.error.message);
		}
		request.onsuccess = function(){
			db = request.result;
			console.log('success open');
			addData(); 
		}
		request.onupgradeneeded = function(){
			var store = null;
			db = request.result;
			if(!db.objectStoreNames.contains(storeName)){	//当要创建的表不存在时
				store = db.createObjectStore(storeName,{autoIncrement: true}); //创建objectStore
				store.createIndex('idIndex','id',{unique: true}); //创建id索引
				store.createIndex('attrIndex','attr',{unique: false}); //创建星座属性索引
				store.createIndex('labelIndex','label',{multiEntry: true}); //创建角色标签索引
			}
			console.log('DB verson changed to '+verson);
		}
	}

	openDB(dbName);

	var data = [
		{
			name: '穆',
			id: 1,
			job: '白羊座黄金圣斗士',
			attr: '火',
			label: ['肉盾','反伤','群攻','念攻'],
		},
		{
			name: '阿鲁迪巴',
			id: 2,
			job: '金牛座黄金圣斗士',
			attr: '土',
			label: ['肉盾','单体','物攻']
		},
		{
			name: '撒加',
			id: 3,
			job: '双子座黄金圣斗士',
			attr: '风',
			label: ['群攻'],
		},
		{
			name: '迪斯马斯克',
			id: 4,
			job: '巨蟹座黄金圣斗士',
			attr: '水',
			label: ['群攻','念攻'],
		},
		{
			name: '艾奥里亚',
			id: 5,
			job: '狮子座黄金圣斗士',
			attr: '火',
			label: ['群攻','物攻'],
		},
		{
			name: '沙加',
			id: 6,
			job: '处女座黄金圣斗士',
			attr: '土',
			label: ['群攻','念攻','控制'],
		},
		{
			name: '童虎',
			id: 7,
			job: '天秤座黄金圣斗士',
			attr: '风',
			label: ['群攻','念攻'],
		},
		{
			name: '米罗',
			id: 8,
			job: '天蝎座黄金圣斗士',
			attr: '水',
			label: ['单体','物攻','爆发'],
		},
		{
			name: '艾俄洛斯',
			id: 9,
			job: '射手座黄金圣斗士',
			attr: '火',
			label: ['单体','物攻','爆发'],
		},
		{
			name: '修罗',
			id: 10,
			job: '摩羯座黄金圣斗士',
			attr: '土',
			label: ['单体','多段','物攻','爆发'],
		},
		{
			name: '卡妙',
			id: 11,
			job: '水瓶座黄金圣斗士',
			attr: '风',
			label: ['控制','念攻'],
		},
		{
			name: '阿布罗狄',
			id: 12,
			job: '双鱼座黄金圣斗士',
			attr: '水',
			label: ['单体','多段','物攻','爆发'],
		},
	];

	function addData(){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		data.map(function(o){
			store.add(o);
		});
	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第14张图片

objectStore下多出了3个索引
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第15张图片
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第16张图片
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第17张图片

4.5.2 索引的相关方法
  • 查询一条数据 IDBIndex.get(‘索引值’)
  • 查询所有数据 IDBIndex.getAll(‘索引值’)
  • 打开游标 IDBIndex.openCursor
  • IDBIndex就是 IDBobjectStore.index('游标名称') 获取的,也就是说也要通过事务

4.5.3 使用索引获取数据

索引可以按值搜索,但是**索引不能操作数据,而游标可以**

//获取所有标签为 群攻 的圣斗士的信息
	function useIndexGetAllData(){
		var transaction = db.transaction(storeName, 'readwrite'),
			store = transaction.objectStore(storeName),
			index = store.index('labelIndex');
			request = index.getAll('群攻');

			request.onsuccess = function(){
				console.log(request.result);
			}
	}

//获取一条标签为 群攻 的圣斗士信息
	function useIndexGetData(){
		var transaction = db.transaction(storeName, 'readwrite'),
			store = transaction.objectStore(storeName),
			index = store.index('labelIndex');
			request = index.get('群攻');

			request.onsuccess = function(){
				console.log(request.result);
			}
	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第18张图片
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第19张图片


4.6 游标

如果我们想要获取objectStore中一个指定区间的数据而不是所有数据,可以使用游标。或者是操作通过索引查询出的数据,也可以使用游标。

也就是说游标也就是一个可以增强增删改查的工具,objectStore和索引都可以创建游标

4.6.1 创建游标

IDBObjectStore/IDBIndex.openCursor(range,direction); //也就是说还是要通过事务
  • 返回一个IDBRequest对象(异步)
  • 参数range:使用的是IDBKeyRange对象的方法
    1. upperBound(“x”,true/false) 指定游标范围上限,true为开区间,默认false闭区间。
    2. lowerBound(“x”,true/false) 指定游标范围下限
    3. only(“x”) 指定游标的值
    4. bound(“x”,“y”,true/false,true/false) 指定游标范围的区间
Range Code
all keys <= x upperBound(x)
all keys < x upperBound(x,true)
all keys >= y lowerBound(y)
all keys > y lowerBound(y,true)
the key = z only(z)
x<=all keys <=y bound(x,y)
x bound(x,y,true,true)
x bound(x,y,ture,false)
x<=all keys bound(x,y,false,true)
  • 参数direction:设置查询的顺序
    1. next:顺序查询。
    2. nextunique:顺序唯一查询。
    3. prev:倒叙查询。
    4. prevunique:倒叙唯一查询。

4.6.2 通过游标获取数据

4.6.2.1无参数
	function useCursorGetData(){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);

		request = store.openCursor(); //创建游标,并且不带参数

		request.onsuccess = function(){
			var cursor = request.result;	//获取游标
			if(cursor){
				console.log(cursor.value);
				cursor.continue(); //遍历数据
			}
		}
	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第20张图片

4.6.2.2指定范围
	function useCursorGetData(id){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);

		request = store.openCursor(IDBKeyRange.only(id)); //创建游标

		request.onsuccess = function(){
			var cursor = request.result;	//获取游标
			if(cursor){
				console.log(cursor.value);
				cursor.continue(); //遍历数据
			}
		}
	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第21张图片


4.6.2.3指定顺序
	function useCursorGetData(){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);

		request = store.openCursor(null,'prev'); //创建游标

		request.onsuccess = function(){
			var cursor = request.result;	//获取游标
			if(cursor){
				console.log(cursor.value);
				cursor.continue(); //遍历数据
			}
		}
	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第22张图片


4.7 使用索引和游标进行复杂的数据操作

案例1
给前六宫的黄金圣斗士打上现在召唤的标签

	function useIndexAndCursorOperateData1(){
		var transaction = db.transaction(storeName, 'readwrite');
		var store = transaction.objectStore(storeName);
		var index = store.index('idIndex');
		var request = index.openCursor(IDBKeyRange.bound(1,6,false,false));	//在索引下也是可以创建游标的 效果和 store.openCursor() 一样

		request.onsuccess = function(){
			var cursor = request.result;
			if(cursor){
				var value = cursor.value;
				value.label.push('限时召唤');	//给前6个圣斗士打上 “限时召唤” 的标签
				cursor.update(value);
				console.log(cursor);
				cursor.continue();
			}
		}
	}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第23张图片
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第24张图片


案例2
给标签带有念攻的角色加上念力穿透这个标签

	function useIndexAndCursorOperateData2(){
		var transaction = db.transaction(storeName ,'readwrite');
		var store = transaction.objectStore(storeName);
		var index = store.index('labelIndex');
		var request = index.openCursor(IDBKeyRange.only('念攻'));

		request.onsuccess = function(){
			var cursor = request.result;
			if(cursor){
				var value = cursor.value;
				value.label.push('念力穿透');
				cursor.update(value);
				console.log(cursor);
				cursor.continue();
			}
		}

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第25张图片

总结:索引是ObjectStore下的,需要通过ObjectStore才能获取指定的索引,而游标是一个强化查询(增删改查)的工具,ObjectStore和索引都可以用。


4.8 indexedDB与Web Storage(localStorage和sessionStorage)比较

IndexedDB的优势

  • 存储类型更加丰富
  • 可实现复杂的查询
  • 可在Web Workers中使用 -存储容量更大

Web Storage的优势

  • API较少,更容易掌握
  • 兼容性更好

二、离线存储

1.Application Cache功能

  • 可永久存储资源
  • 被存储的资源可以离线使用
  • 可通过配置文件修改存储策略

1.1开启web服务器配置

我使用的是wamp,apache的版本是2.4.27。
找到wamp的安装目录下wamp\bin\apache\apache2.4.27\conf的mime.types文件。
添加一行text/cache-manifest appcache(一般情况都是已经有的)
HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第26张图片
配置好后浏览器才会认为manifest文件是个清单文件。

1.2manifest(清单)文件配置

  • CACHE MANIFEST:文件起始标记
  • CACHE:需要缓存文件标记
  • NETWORK:网络请求标记
  • FALLBACK:资源失效回退标记
  • 使用#进行注释

manifest.appcache文件(文件名随便起,但是后缀要是.appcache)

CACHE MANIFEST

#VERSION 1.0

CACHE:
./public/img/test.png
./public/js/test.js

FALLBACK:

NETWORK:
*

1.3.html文件中配置

在html标签中加上manifest属性


<html lang="en" manifest="manifest.appcache">
<head>
	<meta charset="UTF-8">
	<title>测试title>
head>
<body>
	<img src="./public/img/test.png" alt="">
	<script src="./public/js/test.js">script>
body>
html>

HTML5 进阶(1)——HTML5存储(本地存储:localStorage、sessionStorage、indexedDB; 离线存储:Application Cache)_第27张图片

关闭服务器后,访问该页面,是依旧可以访问的。

2.application cache糟糕之处

  1. 文件总是来自缓存,即使在线环境
  2. 资源更新只在manifest文件更新之后
  3. 别忘记给所有缓存文件加上HTTP缓存控制
  4. 未被缓存的资源必须在NETWORK中指明
  5. 无法分辨响应式资源

所以不推荐使用application cache做离线存储

3.service worker

service worker的诸多功能
1、离线缓存
2、消息推送
3、后台消息传递
4、网络代理,转发请求,伪造响应


service worker 离线存储功能的优势

1、可以更细致的控制存储资源
2、拥有强大的更新机制

但是目前service worker的兼容性不好。而且需要https协议。

service worker的示例
https://mdn.gothub.io/sw-test/

你可能感兴趣的:(HTML5,前端)