項目實戰之本地存儲篇

在前端項目開發中,前端的本地存儲是必不可少的,今天小編就前端的本地存儲在項目中的使用詳細的介紹一下。前端本地存儲主要有:html

  • cookie
  • localStorage
  • sessionStorage
  • webSQL/indexDB

接下來就這幾種前端經常使用的存儲方式進行介紹。前端

cookie

cookie就是存儲在客戶端的一小段文本,大小不能超過4kb,在請求接口的時候,cookie會被請求攜帶着,進而被服務器所讀取使用。
打開瀏覽器控制檯,F12>>Application>>Cookies,隨便選擇一個域,咱們能夠看到裏面有不少cookie,以下所示:html5

主要屬性

  • Name
cookie的名稱
  • Value
cookie的值,大小最大4Kb
  • Domain
cookie存儲的域名
  • Path
cookie存儲的路徑
  • Size
cookie的大小
  • Expires/Max-Age
這兩個屬性涉及到 cookie 的存活時間

Expires 屬性指定一個具體的到期時間,到了這個指定的時間以後,瀏覽器就再也不保留這個 cookie ,它的值是 UTC 格式,可使用 Date.prototype.toUTCString() 格式進行轉換。web

Max-Age 屬性制定了從如今開始 cookie 存在的秒數,好比 60 * 60 (即一小時)。過了這個時間之後,瀏覽器就再也不保留這個 Cookie。sql

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,存儲的時候,僅僅在客戶端存儲,不會隨着請求的調用而傳遞到服務器。api

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操做類】獲取

以上就是我對前端本地存儲的一些理解和整理,若有錯,歡迎各位大佬指正,省得誤人子弟~嘿嘿。

參考:
一、indexDB講解與封裝 https://www.jianshu.com/p/136...

相關文章
相關標籤/搜索