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 の表の行と列を結合する問題の解決策の詳細な説明

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

推薦する

HTML でのテキストエリアの使用と一般的な問題およびケース分析

textarea タグはよく使われる HTML タグです。主に長いテキストを入力するときに改行するた...

負のマージントップ値は、ラベルテキストと入力の間の垂直中央揃えの問題を解決します。

ラベルテキストと入力の垂直方向の中央揃えを調整するのは簡単ではありません。padding、verti...

Linux で大きなファイルの指定された内容を見つける方法

大きなことも小さなことも考えて、方向転換しましょう。 Linux では非常に大きなファイルに遭遇する...

MySQLで大きなテーブルを正常に削除する方法の詳細な説明

序文テーブルを削除するには、無意識に思い浮かぶコマンドは、DROP TABLE "テーブル...

DockerにNginxをインストールする方法

DockerにNginxをインストールするNginx は、IMAP/POP3/SMTP サービスも提...

Gitコミットログの変更方法のまとめ

ケース1: 最後の提出とプッシュなし次のコマンドを実行します。 git コミット --amend g...

MySQL でテーブル データを削除した後もディスク領域がまだ占有されているのはなぜですか?

目次1.MySQLデータ構造2. テーブルファイルのサイズは変更されておらず、MySQLの設計に関連...

grep を使用して MySQL エラー ログ情報を取得する方法の詳細な説明

MySQL のメンテナンスを容易にするために、エラー情報を収集するためのインターフェースを提供するス...

Win10 MySQLでCSVをエクスポートする2つの方法

Win10 で csv をエクスポートする方法は 2 つあります。1 つ目はツールを使用することです...

JavaScriptのonclickとclickの違いの詳細な説明

目次addEventListener が必要な理由は何ですか? addEventListener を...

Maxwell を使用して MySQL データをリアルタイムで同期する方法

目次マクスウェルについてMaxwellの設定と使用1. Maxwellインストールパッケージをダウン...

openlayers6のマップオーバーレイの詳細な説明

1. オーバーレイの概要オーバーレイとは、その名の通り、別の形で地図上に表示される、覆うことを指しま...

Zookeeper 不正アクセス テストの問題

目次序文Zookeeper サービスのオープンを検出情報を入手する接続テスト接続先修理計画参照する序...

MySql マスタースレーブレプリケーションメカニズムの包括的な分析

目次マスタースレーブレプリケーションメカニズム非同期レプリケーション準同期レプリケーションマスタース...

MacにHomebrewをインストールする際の注意点

最近、Xiao Ming は新しい Mac を購入し、独自のブログ Web サイトを構築したいと考え...