Typescriptを使用してローカルストレージをカプセル化する方法

Typescriptを使用してローカルストレージをカプセル化する方法

序文

ローカルストレージはフロントエンド開発でよく使われる技術ですが、公式APIは使いにくく、有効期限の設定など一部の機能では対応するAPIが提供されていません。この記事は、ローカル ストレージの概念に関連する知識を紹介することを目的としているのではなく、TypeScript を使用して便利なローカル ストレージ クラスをカプセル化することを目的としています。

ローカルストレージの使用シナリオ

  • ユーザーログイン後のトークン保存
  • ユーザー情報の保存
  • 異なるページ間の通信
  • redux 永続性、vuex 永続性などのプロジェクト ステータス管理の永続性。
  • パフォーマンスの最適化など
  • ...

使用上の問題

  • 公式 API はあまりユーザーフレンドリーではなく (長すぎる)、すべてのデータは文字列の形式で保存され、アクセスするにはデータ型の変換が必要です。
    • localStorage.setItem(キー、値)
    • ...
  • 有効期限を設定できません
  • プレーンテキストで保存されているため、比較的プライベートな情報もブラウザで簡単に閲覧できる。
  • 同じオリジンのプロジェクトはローカルストレージスペースを共有するため、データの混乱が生じる可能性があります。

解決

上記の問題に対する解決策はクラスにカプセル化され、直接呼び出すためのシンプルなインターフェースを通じてユーザーに公開されます。 このクラスは次の機能をカプセル化します。

  • データ型変換
  • 有効期限
  • データ暗号化
  • 統一された命名規則

機能性

// ストレージ.ts

列挙型ストレージタイプ{
  l = 'ローカルストレージ',
  s = 'セッションストレージ'
}

クラスMyStorage {
  ストレージ: ストレージ

  コンストラクター(型: StorageType) {
    this.storage = type === StorageType.l ? window.localStorage : window.sessionStorage
  }

  セット(
    キー: 文字列、
    値: 任意
  ){
    定数データ = JSON.stringify(値)
    this.storage.setItem(キー、データ)
  }

  get(キー: 文字列) {
    定数値 = this.storage.getItem(キー)
    if (値) {
      JSON.parse(値)を返す
  }

  削除(キー: 文字列) {
    this.storage.removeItem(キー)
  }

  クリア() {
    this.storage.clear()
  }
}

const LStorage = 新しい MyStorage(StorageType.l)
const SStorage = 新しい MyStorage(StorageType.s)

エクスポート { LStorage、SStorage }

上記のコードは、ローカルストレージの基本的な機能を単純に実装し、アクセス時に内部でデータ型の変換操作を完了します。使用方法は次のとおりです。

 './storage' から { LStorage, SStorage } をインポートします

...

LStorage.set('data', { name: 'zhangsan' })
LStorage.get('data') // { 名前: 'zhangsan' }

有効期限を追加

有効期限を設定するアイデアは次のとおりです。設定時に、データにexpiresフィールドを追加して、データの保存時間を記録します。取得時に、取得したexpiresを現在の時刻と比較します。現在の時刻がexpiresより大きい場合は、有効期限が切れていることを意味します。この時点で、データレコードをクリアし、nullを返します。expires型は、ブール型と数値型にすることができます。デフォルトはfalse、つまり有効期限は設定されていません。ユーザーがtrueに設定すると、デフォルトの有効期限は1年になります。ユーザーが特定の値に設定すると、有効期限はユーザーが設定した値になります。コードは次のように実装されます。

インターフェースIStoredItem{
  値: 任意
  有効期限: 数値
}
...
セット(
    キー: 文字列、
    値: 任意、
    有効期限: ブール値 | 数値 = false、
  ){
    const ソース: IStoredItem = { 値: null }
    (期限切れ)の場合{
    // デフォルトの有効期限は1年ですが、実際の状況に応じて調整できます。source.expires =
        新しい日付().getTime() +
        (有効期限 === true ? 1000 * 60 * 60 * 24 * 365 : 有効期限)
    }
    ソース.値 = 値
    const データ = JSON.stringify(ソース)
    this.storage.setItem(キー、データ)
  }
  
  get(キー: 文字列) {
    定数値 = this.storage.getItem(キー)
    if (値) {
      定数ソース: IStoredItem = JSON.parse(値)
      const 有効期限 = source.有効期限
      const now = 新しい Date().getTime()
      if (有効期限 && 現在 > 有効期限) {
        this.delete(キー)
        nullを返す
      }

      ソース値を返す
    }
  }

データ暗号化を追加する

暗号化には crypto-js パッケージが使用されます。2 つのプライベート メソッド encrypt と decrypt がクラスにカプセル化され、データの暗号化と復号化を処理します。もちろん、ユーザーは暗号化フィールドを使用してデータを暗号化するかどうかを設定することもできます。デフォルトは true で、暗号化がデフォルトで有効になっていることを意味します。また、現在の環境は process.env.NODE_ENV を通じて取得できます。開発環境の場合は、開発とデバッグを容易にするために暗号化されません。コードは次のように実装されています。

 'crypto-js' から CryptoJS をインポートします。

定数SECRET_KEY = 'nkldsx@#45#VDss9'
定数 IS_DEV = process.env.NODE_ENV === '開発'
...
クラスMyStorage {
  ...
  
  プライベート暗号化(データ: 文字列) {
    CryptoJS.AES.encrypt(data, SECRET_KEY).toString() を返します。
  }

  プライベート復号化(データ: 文字列) {
    定数バイト = CryptoJS.AES.decrypt(データ、SECRET_KEY)
    bytes.toString(CryptoJS.enc.Utf8) を返します
  }
  
  セット(
    キー: 文字列、
    値: 任意、
    有効期限: ブール値 | 数値 = false、
    暗号化 = true
  ){
    const ソース: IStoredItem = { 値: null }
    (期限切れ)の場合{
      ソース.有効期限 =
        新しい日付().getTime() +
        (有効期限 === true ? 1000 * 60 * 60 * 24 * 365 : 有効期限)
    }
    ソース.値 = 値
    const データ = JSON.stringify(ソース)
    this.storage.setItem(キー、IS_DEV? データ: 暗号化? this.encrypt(データ): データ
    )
  }
  
  get(キー: 文字列、暗号化 = true) {
    定数値 = this.storage.getItem(キー)
    if (値) {
      定数ソース: IStoredItem = JSON.parse(値)
      const 有効期限 = source.有効期限
      const now = 新しい Date().getTime()
      if (有効期限 && 現在 > 有効期限) {
        this.delete(キー)
        nullを返す
      }

      IS_DEVを返す
        ? ソース値
        : 暗号化
        ? this.decrypt(ソース.値)
        : ソース.値
    }
  }
  
}

命名規則を追加する

プロジェクト名_バージョン番号_キー型の複合キーなど、キーの前にプレフィックスを追加することで、命名を標準化できます。この命名規則は、定数または package.json で名前とバージョンを連結することで自由に設定できます。コードは次のとおりです。

 const config = require('../../package.json')

const PREFIX = config.name + '_' + config.version + '_'

...
クラスMyStorage {

  // キーを合成
  プライベート合成キー(キー: 文字列) {
    PREFIX + キーを返す
  }
  
  ...
  
 セット(
    キー: 文字列、
    値: 任意、
    有効期限: ブール値 | 数値 = false、
    暗号化 = true
  ){
    ...
    this.storage.setItem() は、
      this.synthesisKey(キー)、
      IS_DEV ? データ: 暗号化? this.encrypt(data): データ
    )
  }
  
  get(キー: 文字列、暗号化 = true) {
    定数値 = this.storage.getItem(this.synthesisKey(key))
    ...
  }

}

完全なコード

'crypto-js' から CryptoJS をインポートします
const config = require('../../package.json')

列挙型ストレージタイプ{
  l = 'ローカルストレージ'、
  s = 'セッションストレージ'
}

インターフェースIStoredItem{
  値: 任意
  有効期限: 数値
}

定数SECRET_KEY = 'nkldsx@#45#VDss9'
const PREFIX = config.name + '_' + config.version + '_'
定数 IS_DEV = process.env.NODE_ENV === '開発'

クラスMyStorage {
  ストレージ: ストレージ

  コンストラクター(型: StorageType) {
    this.storage =
      タイプ === StorageType.l ? window.localStorage : window.sessionStorage
  }

  プライベート暗号化(データ: 文字列) {
    CryptoJS.AES.encrypt(data, SECRET_KEY).toString() を返します。
  }

  プライベート復号化(データ: 文字列) {
    定数バイト = CryptoJS.AES.decrypt(データ、SECRET_KEY)
    bytes.toString(CryptoJS.enc.Utf8) を返します
  }

  プライベート合成キー(キー: 文字列) {
    PREFIX + キーを返す
  }

  セット(
    キー: 文字列、
    値: 任意、
    有効期限: ブール値 | 数値 = false、
    暗号化 = true
  ){
    const ソース: IStoredItem = { 値: null }
    (期限切れ)の場合{
      ソース.有効期限 =
        新しい日付().getTime() +
        (有効期限 === true ? 1000 * 60 * 60 * 24 * 365 : 有効期限)
    }
    ソース.値 = 値
    const データ = JSON.stringify(ソース)
    this.storage.setItem() は、
      this.synthesisKey(キー)、
      IS_DEV ? データ: 暗号化? this.encrypt(data): データ
    )
  }

  get(キー: 文字列、暗号化 = true) {
    定数値 = this.storage.getItem(this.synthesisKey(key))
    if (値) {
      定数ソース: IStoredItem = JSON.parse(値)
      const 有効期限 = source.有効期限
      const now = 新しい Date().getTime()
      if (有効期限 && 現在 > 有効期限) {
        this.delete(キー)
        nullを返す
      }

      IS_DEVを返す
        ? ソース値
        : 暗号化
        ? this.decrypt(ソース.値)
        : ソース.値
    }
  }

  削除(キー: 文字列) {
    this.storage.removeItem(this.synthesisKey(キー))
  }

  クリア() {
    this.storage.clear()
  }
}

const LStorage = 新しい MyStorage(StorageType.l)
const SStorage = 新しい MyStorage(StorageType.s)

エクスポート { LStorage、SStorage }

要約する

Typescript を使用してローカル ストレージをカプセル化する方法については、これで終わりです。Typescript のカプセル化ローカル ストレージに関する関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

<<:  HTML の表の行と列を結合する問題の解決策の詳細な説明

>>:  クールな点滅アラームボタンをおすすめします

推薦する

MySQLプリコンパイル機能の詳細な説明

この記事では、MySQLのプリコンパイル機能について紹介します。具体的な内容は以下のとおりです。 1...

素晴らしいCSS属性MASKの詳しい説明

この記事では、CSS の非常に興味深い属性マスクを紹介します。名前が示すように、マスクはマスクと翻訳...

MySQLのあいまいクエリインデックスの失敗の問題を解決するいくつかの方法

% ワイルドカードを使用すると、インデックス失敗の問題が発生することがよくあります。ここでは、lik...

CSS における px、em、rem、pt の特徴、違い、変換について詳しく説明します。

コンセプト紹介: 1. px (ピクセル):仮想的な長さの単位で、コンピュータ システムのデジタル画...

Vue 開発ツリー構造コンポーネント (コンポーネント再帰)

この記事では、Vue開発ツリー構造コンポーネントの具体的なコードを例として紹介します。具体的な内容は...

Centos7 に Docker をインストールします (2020 の最新バージョンが利用可能、コピーして貼り付けるだけ)

操作については、こちらの公式ドキュメントを参照してください。インストール1. 古いバージョンの do...

Docker と Intellij IDEA の融合により、Java 開発の生産性が 10 倍向上

目次1. 開発前の準備2. 新しいプロジェクトIdea は Java 開発のための強力なツールであり...

MySQLで最新のトランザクションIDを照会する方法

前に書いた内容: ビジネス ロジックの判断を行うために、最新のトランザクション ID を表示する必要...

MySQL ビューの一貫性を確保する方法の詳細な説明 (チェック オプション付き)

この記事では、例を使用して、MySQL ビューの一貫性を確保する方法 (チェック オプションを使用)...

Vueでタイマーをエレガントにクリアする方法

目次序文最適化派生的な質問: beforeDestroy はトリガーされませんか?序文タイマーをクリ...

HTML thead タグの定義と使用法の詳細な紹介

コードをコピーコードは次のとおりです。 <thead> <!– 最初の 2 行をヘ...

Docker は次の「Linux」になれるか?

Linux オペレーティング システムは過去 20 年間にわたってデータ センターに革命をもたらし...

JavaScript 基礎シリーズ: 関数とメソッド

目次1. 関数とメソッドの違い2. 良い関数の書き方2.1 正確な命名2.1.1 関数の命名2.1....

MySQLで判定文を書く方法のまとめ

MySQL で判断文を書く方法:方法1. CASE関数case関数の構文: CASE条件 値1の場合...

JSにおける4つのデータ型判定方法

目次1. 型2. インスタンス3. コンストラクター4.toString() この記事では、4 つの...