客户端存储技术(cookie、sessionStorage、localStorage、indexedDB)

cookie

使用客服端存储的一个好处是不通过网络发送数据,来回通过http header发送cookie信息恰好违背了这一点,所以一般情况下不建议使用cookie存储,但是如果你希望有一些值是服务器应该知道的,那么就可以使用cookie确保服务器看到。cookie存储限制一般为4KB。

一、查看http中的cookie信息

存在cookie的信息会在http请求的时候携带到服务器,可在request headers中查看

二、cookie的使用

1.设置cookie(cookie没有api,所以直接访问document.cookie对象)

//设置第一个cookie
document.cookie = "nameOfCookie=value";

//设置第二个cookie,expires为过期时间,domain可以设置对某个子域名有效(默认只对当前域名有效)
document.cookie = "name=Raymond;expires=Fri,31 Dec 9999 23:59:59 GMT;
domain=app.foo.com";

//动态定义cookie,需要使用类似encodeURIComponent的辅助函数,如
var name = "Raymond Camden";
document.cookie = "name=" + encodeURIComponent(name);

2.读取cookie

//读取出来的cookie包含所有信息,需要通过指定字符串分割获取
console.log(document.cookie)

3.删除cookie(只需要将过期时间设为过去时间即可)

document.cookie = "name=Raymond; expires=Thu, 01 Jan 1970 00:00:00 GMT";

web存储(localStorage和sessionStorage)

web存储有两个版本:本地存储(local storage)和会话存储(session storage)。两者是使用方式是完全一样的,区别在于:本地存储是持久存在的(或者用户主动删除),而会话存储是只要浏览器关闭就会消失。和cookie类似,web存储也是与域名一一对应的。和cookie不同的是,主域名无法和子域名共享存储的数据(可以借助iframe变通实现)。web存储限制一般为5-10MB。

一、使用方式

注意:web存储会将所有的数据都作为字符串存储,包括数字。如若存储引用数据类型,可以配合JSON.stringfy与JSON.parse使用

//存
sessionStorage.setItem("name", "张三");
//取
sessionStorage.getItem("name");
//删除
sessionStorage.removeItem(name);
//删除全部
sessionStorage.cleat();


/*
* 引用类型存储方式
*/

//存
sessionStorage.setItem("userInfo",JSON.stringify({"name":"张三","age":18});
//取
JSON.parse(sessionStorage.getItem("userInfo"));

二、存储事件

存储事件只有在浏览器的另外一个实例修改存储时,才会被触发(只要另外打开一个浏览器,输入相同的URL,在心打开的页签中修改存储的值,然后返回原来的页签,就能看到存储事件本身的信息)。不过,即使能监听到存储发生了变化,也不能再根据不同的页签存储不同的数据了,因为存储系统已经变了,这是不可逆的。唯一可以做的就是,监听存储事件获取最新的值并更新响应的页面数据。

1.代码示例
//监听sotrage变化
window.addEventListener('storage', function (e) {
    console.log(e.key) //key
    console.log(e.newValue) //新值
    console.log(e.oldValue) //旧值  
})

IndexedDB 

indexedDB是和域名一一对应的,它对存储大小及存储的数据类型没有任何限制,可以将它看成是一个数据库的存在。

也可以使用Dexie.js第三方库,官网地址Dexie.js - Minimalistic IndexedDB Wrapper

 一、检查浏览器是否支持indexedDB

//  检查是否支持并且判断当前设备是否为ipad或者iphone
function idbOK() {
 return "indexedDB" in window && !/iPad|iPhone|iPod/.test(navigator.platform);;
}

二、使用IndexedDB

注意:indexedDB中所有的操作都是异步的。因此打开数据库并不代表立即就可以使用,而是需要通过一个响应事件之后才可以使用。

1.打开一个数据库

 需要设置一个名称和版本号,版本号通常从1开始,数据库结构(指对象存储和索引,而不是数据本身)只能在更改版本时调整。

//打开数据库,设置数据库名称为ora_db1,版本号为1
var openRequest = indexedDB.open("ora_db1",1); 

打开数据库可以触发的事件有:

  • success //成功
  • error //失败
  • upgradeneeded  //在用户首次访问数据库或版本号发生变化时触发
  • blocked //数据库不可用时触发

你可以像下面这样考虑这个过程:

  1. 请求打开数据库; 
  2. 如果请求触发了一个upgradeneeded事件,则创建对象存储; 
  3. 如果请求触发了一个success事件,则表明数据库已经准备就绪。
2. 创建一个空的存储对象

注意:创建对象存储必须在upgradeneeded事件中完成。

        2.1 创建对象存储并定义主键

使用createObjectStore()方法创建对象存储,支持传递两个参数

  1. name 对象名称
  2. options 定义对象存储的各种配置属性,包括索引(每条数据中的唯一值)
    keyPath  包含唯一信息的属性且此值不能为空
    autoIncrement 使用自增值自动为主键赋值,如果同时定义了keyPath则会将自增值存储在keyPath定义的属性中。   
var peopleOS=objectStore.createObjectStore("people", {keyPath: "id", autoIncrement:true});
        2.2. 定义索引(非必须

        在指定了存储对象主键后可以定义索引,它能定义你将如何从对象存储中获取数据。

使用createIndex()方法创建索引,支持传递三个参数

  1. name 索引名称
  2. path   希望索引的数据属性,大多数情况下,和第一个参数使用相同的值
  3. options  定义如何操作索引,只有两种:一种指定唯一性,另一种专门用于映射到数据的数据{multientry:true}
//指定索引为性别且不唯一
peopleOS.createIndex("sex", "sex", {unique:false}); 
//指定索引为证件号且唯一
peopleOS.createIndex("ssn", "ssn", {unique:true});   
//指定索引为爱好
peopleOS.createIndex("hobbies", "hobbies", {unique:false,multiEntry:true}); 

3.操作数据(CRUD)

注意:

1.只有当onsuccess处理器运行,才可以开始操作数据。

2. indexedDB的所有数据操作都是在事物中完成的,如果一个事物中的某个操作出现问题,那么任何修改都会回滚。

3. 事物特定于一个或者多个对象存储(指你需要操作的存储对象),这些存储对象可以是只读的(用于获取数据),也可以为读写的(用于修改数据)。

4. CRUD之前都必须要创建事物,并定义需要操作的存储对象及事物类型(读写操作)。

        3.1 创建数据

使用store.add()创建数据,支持两个参数

  1. data  数据(必填),可以为任意类型
  2. somekey  主键

添加数据也是异步的,因此,需要监听事件来检查添加状态。

function add(){
    //创建事物并设置操作类型,readwrite:读写,readonly:只读
    //db为数据库打开成功时的数据库对象,为全局变量,在onsuccess函数中进行赋值
    var transaction = db.transaction(["people"],"readwrite");

    //从事务请求对象存储。
    var store = transaction.objectStore("people");

    //数据
    var person = {
        id:1,
        name:"张三",
        ssn:"166575758332344",
        sex:"男",
        email:"56778899@qq.com"
        hobbies:["电影","做饭","美食"],
    }
    //添加,将id设置为主键
    var request = store.add(person);
    
    //添加成功触发
    request.onsuccess = function(){
        
    }
    //添加失败
    request.onerror = function(){
        
    }
}

        3.2 读取数据

使用store.get(key)读取数据

读取数据也是异步的,key为设置的存储对象中的主键

function getLogs(e) {
    //创建事物,并制定存储对象和类型
    var transaction = db.transaction(["people"],"readonly");
    //请求存储对象
    var store = transaction.objectStore("people");
    //获取数据
    var request = store.get(Number(key));
    //获取数据成功
    request.onsuccess = function(e) {
        var result = e.target.result;
        console.dir(result);
    }
    //获取数据失败
    request.onerror = function(e) {
         console.log("Error");
         console.dir(e);
    }
}
        3.3 更新数据

使用store.put(data),依旧是异步

使用方法和store.add一样,需要创建一个事物,然后使用事物返回的存储对象的变量,调用其put方法,也可以使用第二个参数指定主键。

        3.4 删除数据

store.delete(key)  key依旧为主键。

同样,该操作也要在事务中进行,而且也是异步的。

注意:即使删除的主键不存在,删除操作也会触发onsuccess事件处理器。如果想要避免这种情况的话,就需要在删除之前先判断一下要删除的数据是否存在。

4. 获取所有数据

    IndexedDB使用一个名为游标(cursor)的东西遍历存储对象中的数据。可以将游标想象成一只快乐的小海狸,它跑进对象存储,一次取回一条数据。它每取得一条数据就带回来给你,而你又要求它去取下一条。游标可以双向移动,也可以被限制在一定的数据“范围”内。

   和CRUD一样的是,游标也是在事物内使用的。也需要获取一个事物,从这个事物中获取一个存储对象,然后在此基础上打开一个游标。

var transaction = db.transaction(["people"], "readonly");
var objectStore = transaction.objectStore("people");
//打开一个游标
var cursor = objectStore.openCursor();

cursor.onsuccess = function(e) {
    //游标每次只拿取一条数据,res为本次拿到的数据,如果需要所有数据,可以定义一个全局的数据进行push操作
    var res = e.target.result;
    //如果res未定义,表示已经到达了游标末尾
    if(res) {
        //continue方法告诉游标继续去获取下一条
        res.continue();
    }
}

//触发此事件就表示游标遍历已经完成,拿到了
cursor.oncomplete = function(){

}

5.获取指定范围内的数据

· 游标适用于获取所有数据,如果希望只获取部分指定范围内的数据,可以根据索引获取,索引以数据的某个属性为基础,可以从所有数据中筛选出位于指定索引范围内的数据。

· 使用范围和使用游标不同,范围是在索引上打开游标,而不是在对象上。

· 范围是由IDBKeyRange API创建的,该API提供了

        · upperBound("上限")

        · lowerBound ("下限")

        · bound ("上限","下限")

        · only("指定值")

PS:复杂检索不是indexedDB擅长的事件,如:检索id为0-10之间且code为200的数据,indexedDB无法做到。

var maxNum = 10;
var minNum = 2;

if(maxNum != "" && minNum != "") {
    range = IDBKeyRange.bound(minNum, maxNum);
} else if(minNum == "") {
    range = IDBKeyRange.upperBound(maxNum);
} else {
    range = IDBKeyRange.lowerBound(minNum);
}

//创建事物并获取存储对象
var transaction = db.transaction(["people"],"readonly");
var store = transaction.objectStore("people");

//获取索引
var index = store.index("id");

var arr = [];

//在指定范围内打开游标成功触发
index.openCursor(range).onsuccess = function(e) {
    var cursor = e.target.result;
    if(cursor) {
        arr.push(cursor)
        cursor.continue();
    }
}

//游标遍历完成
transaction.oncomplete = function() {
    //没有符合的数据
    if(arr.length == 0){
    }
}

6. 关于indexedDB的更多内容

        6.1 存储数组并根据数组中的指定项来获取数据

如果希望在数组的基础上定义索引,需要使用multiEntry选项

objectStore.createIndex("hobbies", "hobbies", {unique:false, multiEntry:true});

如果希望根据数组中的某一项来进行检索的话,只需要用到IDBKeyRange.only()

//定义检索范围
var range = IDBKeyRange.only(hobby);

//创建事物并定义只读类型
var transaction = db.transaction(["people"],"readonly");
//请求存储对象
var store = transaction.objectStore("people");
//获取索引
var index = store.index("hobbies");
//打开游标成功
index.openCursor(range).onsuccess = function(e) {
    var cursor = e.target.result;
    if(cursor){
        //继续拿取下一条数据
        cursor.continue();
    }
}

//游标遍历完成
transaction.oncomplete = function(){

}
        6.2 计算数据量
//获取存储对象为logsOs的数据量
db.transaction(["people"],"readonly").objectStore("people").count().onsuccess =function(event) {
    console.log('total is '+event.target.result);
}

7.indexedDB完整案例代码

//判断浏览器是否支持indexedDB
function idbOK() {
 return "indexedDB" in window;
}

//全局数据库对象
var db = null;

$(document).ready(function() {
    if(!idbOK()) return; //不支出

    //打开数据库,设置数据库名称为ora_db1,版本号为1
    var openRequest = indexedDB.open("ora_db1",1);
   

    //第一次访问时触发或数据库版本变更后触发
    openRequest.onupgradeneeded = function(e){
        //获取数据库对象本身
        var thisDB = e.target.result;
    
        //判断当前存储中是否存在logs对象,不存在就创建
        if(!thisDB.objectStoreNames.contains("people")){
            //创建存储对象和主键
            var peopleOs = thisDB.createObjectStore("people",{keyPath: "id", autoIncrement:true})
        
            //创建索引 unique指索引值是否唯一,设置数组为索引时需要将multiEntry设为true
            peopleOs.createIndex("name","name",{unique:false});
            peopleOs.createIndex("id","id",{unique:true});
            peopleOs.createIndex("hobbies","hobbies",{unique:false,multiEntry:true});
        
        }

        //判断当前存储中是否存在notes对象,不存在就创建
        if(!thisDB.objectStoreNames.contains("notes")){
            thisDB.createObjectStore("notes");
        }
    };

    //数据库打开成功
    openRequest.onsuccess = function(e){
        db = e.target.result;
    }

    //数据库打开失败
    openRequest.onerror = function(e) {
    
    }
}


//给存储对象中添加数据
function addPeople(e) {
    //获取事务,设置存储对象和类型
    var transaction = db.transaction(["people"],"readwrite");
    //请求objectStore
    var store = transaction.objectStore("people");

    //定义数据
    var person = {
        id:1,
        name:"张三",
        ssn:"166575758332344",
        sex:"男",
        email:"56778899@qq.com"
        hobbies:["电影","做饭","美食"],
    }

    //添加数据并设置主键
    var request = store.add(person);
    
    //失败
    request.onerror = function(e) {
        console.log("Error",e.target.error.name);
    }

    //成功
    request.onsuccess = function(e) {
        console.log("Woot! Did it");
    }
}

//删除
function removePeople(){
    //获取事务,设置存储对象和类型
    var transaction = db.transaction(["people"],"readwrite");
    //请求objectStore
    var store = transaction.objectStore("people");
    
    //根据主键删除数据
    var request = store.delete(key);
    
    //失败
    request.onerror = function(e) {
        console.log("Error",e.target.error.name);
    }

    //成功
    request.onsuccess = function(e) {
        console.log("Woot! Did it");
    }
}

//更新数据
function updatePerson(e) {
    //获取事务,设置存储对象和类型
    var transaction = db.transaction(["people"],"readwrite");
    //请求objectStore
    var store = transaction.objectStore("people");

    //定义数据
    var person = {
        id:1,
        name:"张三",
        ssn:"166575758332344",
        sex:"男",
        email:"56778899@qq.com"
        hobbies:["电影","做饭","美食"],
    }

    //根据id更新数据
    var request = store.put(person,key);
    
    //失败
    request.onerror = function(e) {
        console.log("Error",e.target.error.name);
    }

    //成功
    request.onsuccess = function(e) {
        console.log("Woot! Did it");
    }
}

//获取数据,根据主键读取
function getPeople(){
    //获取事务,设置存储对象和类型
    var transaction = db.transaction(["people"],"readonly");
    //请求objectStore
    var store = transaction.objectStore("people");
    
    //根据主键获取数据
    var request = store.get(key);

    //失败
    request.onerror = function(e) {
        console.log("Error",e.target.error.name);
    }

    //成功
    request.onsuccess = function(e) {
        console.log("Woot! Did it");
    }
}

//获取全部数据----游标(每次只能获取一条数据)
function getAllPeople(){
    //获取事务,设置存储对象和类型
    var transaction = db.transaction(["people"],"readonly");
    //请求objectStore
    var store = transaction.objectStore("people");
    //打开游标
    var cursor = people.openCursor();
    
    let allData = [];
    cursor.onsuccess = function(e){
        var cursor = e.target.result;
        if(cursor){
            //继续去获取下一条
            allData.push(cursor);
            cursor.continue();
        }
    }
        
    //游标遍历完成
    transaction.oncomplete = function(){
        console.log(allData)//打印全部数据
    }
}

//获取指定范围内数据
function search_people(){
    var maxNum = 10;
    var minNUm = 2;
    var range;
    if(minNUm != "" && maxNum != "") {
        range = IDBKeyRange.bound(lower, maxNum); //在上限和下限范围内
    } else if(minNUm == "") {
        range = IDBKeyRange.upperBound(maxNum);//上限
    } else {
        range = IDBKeyRange.lowerBound(minNUm); //下限
        //range = IDBKeyRange.only(minNUm); //只查询符合minNum的数据
    }
    var transaction = db.transaction(["people"],"readonly");
    var store = transaction.objectStore("people");
    var index = store.index("id");
    
    var arr = [];
    index.openCursor(range).onsuccess = function(e) {
        var cursor = e.target.result;
        if(cursor) {
            arr.push(cursor);
            cursor.continue();
        }
    }
    //游标遍历完成
    transaction.oncomplete = function() {
        if(arr.length > 0){
            console.log(arr) //符合范围内的数据
        }
    }
}

//获取数组总量
db.transaction(["people"],"readonly").objectStore("people").count().onsuccess =
function(event) {
    console.log('total is '+event.target.result);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值