1. 程式人生 > 程式設計 >如何使用Vue的思想封裝一個Storage

如何使用Vue的思想封裝一個Storage

目錄
  • 背景
  • 功能
  • 目的
  • 想法來源
  • 實現
    • set
    • get
    • deleteProperty
    • preventExtensions
    • has
  • 總結

    背景

    localStorage、sessionStorage 這兩個 API 是我們前端日常開發中的儲存的利器, 我們經常會使用它們儲存一些資料。我們日常在對他們進行操作的時候,對 localStorage、sessionStorage 的使用一般是直接:

    localStorage.setItem(xxx,xxx);
    sessionStorage.setItem(xxx,xxx);
    localStorage.getItem(xxx);
    sessionStorage.getItem(xxx);
    

    或者有的同學還會這樣簡單封裝一下:

    const getItem = (key) => {
       const serializedValue = window.localStorage.getItem(key) as any;
       return ON.parse(serializedValue);
    };
    const setItem = (key,value) => {
      if (window && window.localStorage) {
        window.localStorage.setItem(key,JSON.stringify(value));
      }
    };
    

    但是這樣使用起來雖然問題不大,但是總感覺程式碼不夠優雅,正好最近封裝了一些底層的基礎庫,就包括了對著兩兄弟的封裝。發現一些比較好玩的東西。小編也是有一些新的體會和想法,分享給大家。

    功能

    • localStorage、sessionStorage 設定
    • localStorage、sessionStorage 獲取
    • localStorage、sessionStorage 刪除一項
    • localStorage、sessionStorage 清空所有儲存

    目的

    封裝一個 localStorage、sessionStorage API,實現對 storage 的增、刪、改、查。

    想法來源

    大家如果使用過 2.0 ,那你一定知道 Object.defineProperty 方法,這個 API 就是 Vue 響應式的核心,用於觀測資料的變化,但是它存在一些弊端:

    • 物件型別資料裡新增一對新的 key/value 或刪除一對已有的 key/value 時,它是無法觀測到的,導致當我們對 object 資料新增或刪除值時,無法通知依賴,無法驅動檢視進行響應式更新。
    • 對於陣列變化偵測是 Vue2.0 通過攔截器實現的,也就是說只要是通過陣列原型上的方法對陣列進行操作就都可以偵測到,但是通過陣列的下標來操作資料,就需要手動去操作了。

    這些問題在 Vue 3.0 得到了解決,解決思路是 ES6 中的方法 Proxy 。

    Proxy 用於修改某些操作的預設行為,等同於在語言層面做出修改,所以屬於一種“元”(meta programming),即對程式語言進行程式設計。

    Proxy 可以理解成,在目標物件之前架設一層“攔截”,外界對該物件的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這裡表示由它來“代理”某些操作,可以譯為“代理器”。

    Proxy 是一個天然的攔截器、代理器,所以我們也可以使用 Proxy 來代理對 localStorage、sessionStorage 的操作。話不多說,直接上程式碼。

    實現

    var proxyStorage = {
      /**
       * 返回 Storage 代理
       * @returns Proxy
       * @example
       * proxyStorage.getStorageProxy(localStorage,'_')
       */
      getStorageProxy: (storage,prefix) => {
        if (!storage)
          return false;
        const getKey = (prop) => `${prefix}.${String(prop)}`;
        return new Proxy(new Object(),{
          /**
           * 設定 storage
           * @returns boolean
           * @example
           * const storageProxy = proxyStorage.getStorageProxy(localStorage,'_');
           * storageProxy.a = 1;
           */
          set(target,prop,value) {
            target[prop] = value;
            storage.setItem(getKey(prop),JSON.stringify(value));
            return true;
          },/**
           * 獲取 storage
           * @returns boolean
           * @example
           * const storageProxy = proxyStorage.getStorageProxy(localStorage,'_');
           * console.log(storageProxy.a);
           */
          get(_,prop) {
            return JSON.parse(storage.getItem(getKey(prop)) || '');
          },/**
           * 刪除 storage
           * @returns boolean
           * @example
           * const storageProxy = proxyStorage.getStorageProxy(localStorage,'_');
           * delete storageProxy.a;
           */
          deleteProperty(_,prop) {
            storage.removeItem(getKey(prop));
            return true;
          },/**
           *http://www.cppcns.com 清空 storage
           * @returns boolean
           * @example
           * const storageProxy = proxyStorage.getStorageProxy(localStorage,'_')http://www.cppcns.com;
           * Object.preventExtensions(storageProxy);
           */
          preventExtensions(target) {
            Object.preventExtensions(target);
            storage.clear();
            return true;
          },/**
           * 查詢 storage
           * @returns boolean
           * @example
           * const storageProxy = proxyStorage.getStorageProxy(localStorage,'_');
           * 'a' in storageProxy;
           */
          has(target,prop) {
            try {
              return !!storage.key(prop);
            } catch (error) {
              return false;
            }
          }
        });
      },};
    
    var proxyStorageTest = proxyStorage.getStorageProxy(localStorage,'_');
    

    利用 Proxy,返回一個 localStorage、sessionStorage 的代理物件,這個代理物件,對 set、get、delete、preventExtensions、in 等操作進行劫持。

    set

    攔截物件屬性的設定,比如 storage.foo = v 或 storage['foo'] = v,返回一個布林值。對代理物件的屬性賦值,攔截這個賦值,操作對應的 storage 的 setItem,就可以直接把值儲存到對應的 storage 中。

    storage.a = 1;
    // or
    storage['a'] = 1;
    

    get

    攔截物件屬性的讀取,比如 storage.foo 和 storage['foo']。讀取代理物件的屬www.cppcns.com性值,攔截這個獲取操作,拿到對應的 key,操作對應的 storage 的 getItem,從相應的 storage 中獲取對應的值。

    console.log(storage.a); // 1
    

    deleteProperty

    攔截 delete storage[propKey]的操作,返回一個布林值。這裡攔截的是物件的刪除資料操作,內部對 storage 進行 removeItem 的操作,刪除資料。

    delete proxyStorageTest.a;
    

    preventExtensions

    攔截 Object.preventExtensions(storage),返回一個布林值。攔截物件的不可擴充套件操作,內部對對應的 storage 進行 clear 操作,來清除所有的儲存值。

    Object.preventExtensions(proxyStorageTest);
    

    has

    攔截 propKey in proxy 的操作,以及物件的 hasOwnProperty 方法,返回一個布林值。攔截物件的查詢屬性的操作,查詢某一個 key 是否存在於對應的 storage 中。

    'a' in proxyStorageTest;
    

    總結

    通過 Proxy 來代理對 localStorage、sessionStorage 的操作,封裝一個 簡單 storage API。Proxy 可用來操作 localStorage、sessionStorage ,也可用來操作 document.cookie 和 indexedDB。當然 Proxy 的功能並不侷限於此,它也還有很多其他的用途,例如 Vue 3.0 中對 Proxy 的使用,亦或者其他,這篇文章重點不在於封裝一個簡單的 API,而是引導大家去學習這種思想。

    到此這篇關於如何使用Vue的思想封裝一個Storage的文章就介紹到這了,更多相關Vue思想封裝Storage內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!