乐趣区

关于javascript:项目实战之本地存储篇

在前端我的项目开发中,前端的本地存储是必不可少的,明天小编就前端的本地存储在我的项目中的应用具体的介绍一下。前端本地存储次要有:

  • cookie
  • localStorage
  • sessionStorage
  • webSQL/indexDB

接下来就这几种前端罕用的存储形式进行介绍。

cookie

cookie 就是存储在客户端的一小段文本,大小不能超过 4kb,在申请接口的时候,cookie 会被申请携带着,进而被服务器所读取应用。
关上浏览器控制台,F12>>Application>>Cookies, 轻易抉择一个域,咱们能够看到外面有很多 cookie,如下所示:

次要属性

  • Name

cookie 的名称

  • Value

cookie 的值, 大小最大 4Kb

  • Domain

cookie 存储的域名

  • Path

cookie 存储的门路

  • Size

cookie 的大小

  • Expires/Max-Age

这两个属性波及到 cookie 的存活工夫

Expires 属性指定一个具体的到期工夫,到了这个指定的工夫之后,浏览器就不再保留这个 cookie , 它的值是 UTC 格局,能够应用 Date.prototype.toUTCString() 格局进行转换。

Max-Age 属性制订了从当初开始 cookie 存在的秒数,比方 60 * 60(即一小时)。过了这个工夫当前,浏览器就不再保留这个 Cookie。

Max-Age 的优先级比 Expires 高,如果两者都不设置,则这个 cookie 会在浏览器敞开的时候生效。

  • HttpOnly

如果设置了该属性,意思就是这个 cookie 不能被 JavaScript 取到,也就避免了 cookie 被脚本读取,而后当发动申请的时候,该 cookie 才会被带上。

  • Secure

指定浏览器只有在加密协议 HTTPS 下能力发送 cookie,不须要设置,当协定是 https 时,会主动开启。

应用形式

  • 设置 cookie
/**
 * 设置 cookie
 * @param {*} key 名称
 * @param {*} val 值
 * @param {*} time 生效工夫
 */

export const setCookie = (key, val, time) => {var date = new Date();

  var expiresDays = time;

  // 将工夫转换为 cookie 设置工夫的格局

  date.setTime(date.getTime() + expiresDays * 24 * 3600 * 1000);

  document.cookie = key + "=" + val + ";expires=" + date.toDateString();}
  • 获取 cookie
/**
 * 获取 cookie
 * @param {*} key 名称
 */

export const getCookie = (key) => {var getCookie = document.cookie.replace(/[]/g, "");

  var arrCookie = getCookie.split(";")

  var tips;

  for (var i = 0; i < arrCookie.length; i++) {var arr = arrCookie[i].split("=");

    if (key == arr[0]) {tips = arr[1];

      break;

    }

  }

  return tips;

}
  • 删除 cookie

删除 cookie 的话,能够间接调用设置 cookie 的办法,将生效工夫置为 -1,如下:

setCookie(key,'',-1)

localStorage/sessionStorage

localStorage/sessionStorage 是在 html5 中新退出的技术,两者除了数据的时效性不一样之外,其余都一样。大小个别为 5MB,存储的时候,仅仅在客户端存储,不会随着申请的调用而传递到服务器。

localStorage 不手动删除则永恒无效,sessionStorage 仅在以后会话无效

上面 F12>>Application>>Cookies 看一个存储示例:

能够看到,其只有两个属性,也就是 key(名称)、value(值)

应用形式

localStorage 和 sessionStorage 都具备雷同的操作方法,例如 setItem、getItem 和 removeItem 等,为了使用方便,咱们对其进行二次封装,示例如下:

  • 存储 Storage
/**
 * 存储 Storage
 */
export const setStore = (params = {}) => {
  let {
    name,// 名称
    content,// 内容
    type,// 类型
  } = params;
  let obj = {dataType: typeof (content),
    content: content,
    type: type,
    datetime: new Date().getTime()
  }
  if (type) window.sessionStorage.setItem(name, JSON.stringify(obj));
  else window.localStorage.setItem(name, JSON.stringify(obj));
}
  • 获取 Storage
/**
 * 判断是否为空
 */
function validatenull (val) {if (typeof val === 'boolean') {return false}
  if (typeof val === 'number') {return false}
  if (val instanceof Array) {if (val.length == 0) return true
  } else if (val instanceof Object) {if (JSON.stringify(val) === '{}') return true
  } else {if (val == 'null' || val == null || val == 'undefined' || val == undefined || val == '') return true
    return false
  }
  return false
}

/**
 * 获取 Storage
 */
export const getStore = (params = {}) => {
  let {
    name,// 名称
    debug// 是否须要转换类型
  } = params;
  let obj = {},
    content;
  obj = window.sessionStorage.getItem(name);
  if (validatenull(obj)) obj = window.localStorage.getItem(name);
  if (validatenull(obj)) return;
  try {obj = JSON.parse(obj);
  } catch{return obj;}
  if (debug) {return obj;}
  if (obj.dataType == 'string') {content = obj.content;} else if (obj.dataType == 'number') {content = Number(obj.content);
  } else if (obj.dataType == 'boolean') {content = eval(obj.content);
  } else if (obj.dataType == 'object') {content = obj.content;}
  return content;
}
  • 删除 Storage
/**
 * 删除 localStorage
 */
export const removeStore = (params = {}) => {
  let {
    name,
    type
  } = params;
  if (type) {window.sessionStorage.removeItem(name);
  } else {window.localStorage.removeItem(name);
  }

}
  • 获取全副 Storage
/**
 * 获取全副 Storage
 */
export const getAllStore = (params = {}) => {let list = [];
  let {type} = params;
  if (type) {for (let i = 0; i <= window.sessionStorage.length; i++) {
      list.push({name: window.sessionStorage.key(i),
        content: getStore({name: window.sessionStorage.key(i),
          type: 'session'
        })
      })
    }
  } else {for (let i = 0; i <= window.localStorage.length; i++) {
      list.push({name: window.localStorage.key(i),
        content: getStore({name: window.localStorage.key(i),
        })
      })

    }
  }
  return list;

}
  • 清空全副 Storage
/**
 * 清空全副 Storage
 */
export const clearStore = (params = {}) => {let { type} = params;
  if (type) {window.sessionStorage.clear();
  } else {window.localStorage.clear()
  }

}

cookie、localStorage、sessionStorage 异同

数据存储工夫

  • cookie 能够本人设置生效工夫
  • localStorage 不被动革除,则永恒存储
  • sessionStorage 以后页面敞开时被删除

大小

  • cookie 最大 4kb
  • localStorage 最大 5MB
  • sessionStorage 最大 5MB

申请是否携带

  • cookie 每次申请会携带在申请头中
  • localStorage 不携带,仅在客户端存储
  • sessionStorage 不携带,仅在客户端存储

易用性

  • cookie 原生 api 应用不敌对,需本人二次封装
  • localStorage 原生接口可应用,也能够本人二次封装
  • sessionStorage 原生接口可应用,也能够本人二次封装

集体举荐在我的项目中应用 storage 存储,cookie 存储数据过多,会造成性能问题。当然,大家能够依据理论状况进行抉择,二次封装办法已双手奉上。

webSQL/indexDB

对于简略的数据存储,storage 和 cookie 就曾经够用了,然而如果须要存储比较复杂的关系型数据,再应用 storage 和 cookie,就有点力不从心了。这个时候能够应用 webSQL 或者 indexDB 进行存储。

webSQL

Web SQL 数据库 API 是一个独立的标准,在浏览器层面提供了本地对结构化数据的存储,曾经被很多古代浏览器反对了。

外围 api
  • openDatabase() => 用来关上或创立数据库(没有时则创立,有则关上)
  • transaction() => 这个办法能够管制一个或多个事务,以及基于这种状况提交或者回滚
  • executeSql() => 用于执行理论的 SQL 查问
判断浏览器是否反对该性能

从下面的图中能够看出,webSQL 兼容性并不是太好,因而应用时,咱们须要先判读那浏览器是否反对。

if (window.openDatabase) {// 操作 web SQL} else {alert('以后浏览器不反对 webSQL !!!');
}
webSQL 操作类封装

webSQL 操作类封装代码量较大,此处就不再展现,须要的小伙伴能够关注我公众号回复【webSQL 操作类】获取。上面给个简略的例子:

var myDB = {
    name: 'formData',
    version: 1,
    db: null,
};
myDB.db = openDatabase(myDB.name, myDB.version, 'test', 100 * 1024 * 1024);
myDB.db.transaction(function(tx) {tx.executeSql('', [], function(tx, result) {if(result.rows.length!=0){//result.rows.item(i)
          }
    }, function(tx, error) {console.log(error);
    });
})

罕用的 SQL 语句:

// 新建表
'CREATE TABLE IF NOT EXISTS 表名 (列名称 1 PRIMARY KEY, 列名称 2 UNIQUE , 列名称 3)'
// 删除表
'DROP TABLE 表名'
// 清空表
'DELETE FROM 表名'
// 删除条目
'DELETE FROM 表名 WHERE 列名称 1 = ? and 列名称 2 = ?'
// 新增一条
'INSERT INTO 表名 VALUES (?,?,?,?,?,?,?)' // 为所有列增加值
'INSERT INTO 表名 (列名称 2, 列名称 4, 列名称 6) VALUES (?,?,?)' // 为指定列增加值
// 批量减少
insert into persons 
(id_p, lastname , firstName, city)
values
(200,'haha' , 'deng' , 'shenzhen'),
(201,'haha2' , 'deng' , 'GD'),
(202,'haha3' , 'deng' , 'Beijing')
// 更新一条
'UPDATE 表名 SET 列名称 1 = ? where 列名称 2 = ? AND 列名称 3 = ?'
'UPDATE 表名 SET 列名称 1 = ?, 列名称 2 = ?, 列名称 3 = ? where 列名称 2 = ? AND 列名称 3 = ?'
 // 依据主键存在与否,更新或增加一条数据
'replace into 表名 (列名称 1, 列名称 2, 列名称 3, 列名称 4, 列名称 5) VALUES (?,?,?,?,?)'
 // 查找(更多查问请依据本人的须要自由组合)'select * from 表名 where 列名称 1 = ? and 列名称 1 >= ?' // 惯例查找
'select * from 表名 where 列名称 1 = ? or 列名称 1 >= ?' // 惯例查找

'select * from 表名 ORDER BY ?' // 指定排序项
'select * from 表名 ORDER BY ? LIMIT 2;'// 只查找符合条件的 2 条

WHERE 列名称 IS NOT NULL // 非空
WHERE 列名称 LIKE "111%" //111 结尾的
WHERE 列名称 LIKE "%111" //111 结尾的
WHERE 列名称 LIKE "%111%" // 蕴含 111 的
WHERE 列名称 NOT LIKE "%111%" // 不蕴含 111 的
'_a_'    // 三位且两头字母是 a 的
'_a'    // 两位且结尾字母是 a 的
'a_'    // 两位且结尾字母是 a 的

WHERE 列名称 GLOB > 111 // 大于 111
WHERE 列名称 GLOB >= 111 // 大于等于 111
WHERE 列名称 GLOB != 111 // 不等于 111 

WHERE 列名称 GLOB '111*' //111 结尾的
WHERE 列名称 IN (25, 27)  // 值为 25 或 27 的
WHERE 列名称 NOT IN (25, 27)  // 值不为 25 或 27 的
WHERE 列名称 BETWEEN 25 AND 27  // 值在 25 到 27 之间的
WHERE 列名称 IN ('25', '27')  // 留神: 拼接 sql 时不要遗记引号

// 索引
'CREATE INDEX IF NOT EXISTS 索引名 on 表名 (列名称 1, 列名称 2)'
'DROP INDEX 索引名'

indexDB

IndexedDB 规范是 HTML5 官网认可的本地数据库解决方案。其目标不是取代服务器端数据库,它在一些特定场景下很有用, 比方离线利用。IndexedDB 是一种轻量级 NOSQL 数据库,是由浏览器自带。相比 Web Sql 更加高效,包含索引、事务处理和查问性能。

从上图能够看出 indexDB 的兼容性还是不错的。

应用 indexDB
创立 / 关上一个数据库

首先咱们须要创立或者关上一个数据库对象,能够应用 window.indexedDB.open() 办法,示例如下:

var openRequest =window.indexedDB.open(name, version);
var db;
openRequest.onupgradeneeded = function(e) {console.log("Upgrading...");}
openRequest.onsuccess = function(e) {console.log("Success!");
  db = e.target.result;
}
openRequest.onerror = function(e) {console.log("Error");
  console.dir(e);
}

第一次关上数据库时,会先触发 upgradeneeded 事件,而后触发 success 事件

open 办法返回的是一个对象(IDBOpenDBRequest),回调函数定义在这个对象下面

回调函数承受一个事件对象 event 作为参数,它的 target.result 属性就指向关上的 IndexedDB 数据库

创立一个存放数据的“对象仓库”

数据库对象有了,咱们还须要创立一个存放数据的“对象仓库”,示例如下:

db.createObjectStore("test", { keyPath: "email"});

db.createObjectStore("test2", { autoIncrement: true});

keyPath 示意的是存储数据的键名,autoIncrement 示意是否应用主动递增的整数作为键名。一般来说,两个属性有一个就能够了。

创立一个数据库事务对象

transaction 办法用于创立一个数据库事务。向数据库增加数据之前,必须先创立数据库务。

transaction 办法返回一个事务对象,该对象的 objectStore 办法用于获取指定的对象仓库。

var transaction = db.transaction(["firstOS"],"readwrite");

var store = transaction.objectStore("firstOS");

transaction 办法承受两个参数:

第一个参数是一个数组,外面是所波及的对象仓库,通常是只有一个;

第二个参数是一个示意操作类型的字符串。readonly(只读)和 readwrite(读写);

transaction 办法有三个事件,能够用来定义回调函数。

abort: 事务中断; complete: 事务实现; error: 事务出错。

transaction.oncomplete = function(event) {// some code};
操作数据

transaction 对象提供了一些 api,供咱们操作数据。

  • 增加数据 add()

获取对象仓库当前,就能够用 add 办法往里面增加数据了, 示例如下:

var transaction = db.transaction(["firstOS"],"readwrite");
var store = transaction.objectStore(“firstOS”);
var data = {name: 'monkey'};
var request = store.add(data,1);
request.onerror = function(e) {console.log("Error",[e.target.error.name](http://e.target.error.name));
}
request.onsuccess = function(e) {console.log("数据增加胜利!");
}

add 办法的第一个参数是所要增加的数据,第二个参数是这条数据对应的键名(key),下面代码将对象 o 的键名设为 1。如果在创立数据仓库时,对键名做了设置,这里也能够不指定键名。

  • 更新数据 put()
var data = {name: 'monkeysoft'};
var request = store.put(data);
  • 读取数据 get()
var request = store.get(key);
  • 删除数据 delete()
var request = store.delete(key);
  • 清空数据库 clear()
var request = store.clear();
  • 遍历数据 openCursor()
var request = store.openCursor();
indexDB 操作类封装

indexDB 操作类封装代码量较大,此处就不再展现,须要的小伙伴能够关注我公众号回复【indexDB 操作类】获取

以上就是我对前端本地存储的一些了解和整顿,如有错,欢送各位大佬斧正,省得误人子弟~ 嘿嘿。

参考:
1、indexDB 解说与封装 https://www.jianshu.com/p/136…

退出移动版