vuex で履歴を実装するためのサンプルコード

vuex で履歴を実装するためのサンプルコード

私は最近、ユーザー操作を元に戻す、またはやり直す機能を備えたビジュアル操作プラットフォームを開発しています。オンラインでいくつかのソリューションを検索し、思い描いたソリューションを完成させました。

履歴記録要件の要点

  • ローカルストレージに保存できる
  • 複数の元に戻す機能とやり直し機能が可能
  • リスト内の項目をクリックすると、履歴を指定した位置に戻ったり進めたりできます。

一見単純な要件ですが、インフラストラクチャ設計のエラーにより、将来的に作業負荷が増大することになります。したがって、上記 2 点の要件を組み合わせると、vuex の基本的な考え方がこの要件を満たすのに非常に適していることがわかります。これは redux にも当てはまります。

実装のアイデア

このプロジェクトでは、コードの厳密性を高め、将来のメンテナンスを容易にするために TypeScript を使用しています。そのアイデアを見てみましょう。

1. まず履歴記録のデータ構造を定義する

インターフェース HistoryItem {
  timestrap: number; // レコードのタイムスタンプ name: string; // レコード名 redo: string; // 変更をやり直す
  undo: string; // 変更を元に戻す
  redoParams: any[]; // Redo Mutation 送信パラメータ undoParams: any[]; // Undo Mutation 送信パラメータ }

インターフェース HistoryStatus {
  historys: HistoryItem[]; // 記録履歴 array_currentHistory: number; // 現在のノードインデックス}

2. 履歴状態モジュールを書く

基本的な操作履歴状態用の vuex モジュールを記述し、記録された変更を作成し、アクションをやり直したり元に戻したりする
レコードには、このステップのやり直し操作の実行と元に戻す操作のキャンセルが含まれます。したがって、ユーザーがリスト内の項目の 1 つをクリックすると、現在の項目の前の項目に戻って元に戻すか、現在の項目にループしてやり直す必要があります。

したがって、ユーザーが空のレコードをクリックして最初の操作を元に戻すことが簡単にできるように、空のレコードを追加する必要があります。

vuex-module-decoratorsを使用して、より保守しやすいコードを書く

「vuex-module-decorators」から VuexModule、Module、Mutation、Action をインポートします。

@Module({名前空間: true })
エクスポートクラス HistoryModule は VuexModule<HistoryStatus> を拡張し、HistoryStatus を実装します {
  /** 
   * 空のレコードを初期化する主な理由は、リスト操作を容易にするためです。
   * ユーザーが最も古いレコードをクリックすると、ユーザーの操作の最初のステップを正常に元に戻すことができます**/
  公開履歴:HistoryItem[] = [
    {
      名前: `Open`、
      タイムストラップ: Date.now(),
      やり直し: "",
      再実行パラメータ: [],
      元に戻す: "",
      元に戻すパラメータ: [],
    },
  ];
  パブリック_currentHistory: 数値 = 0;

  // ゲッター
  現在の値を取得する(){
    this._currentHistory を返します。
  }

  // ゲッター
  historyList() を取得します: HistoryItem[] {
    this.historys || [] を返します。
  }

  // 履歴を作成 @Mutation
  パブリック CREATE_HISTORY(ペイロード: HistoryItem) {
    this._currentHistory < this.historys.length - 1 の場合 {
      this.historys = this.historys.slice(0, this._currentHistory);
    }
    // js の深いコピーと浅いコピーの問題により、作成時にデータを深くコピーする必要があります // lodash の clone 関数を試してみたいのですが、JSON.stringify の clone メソッドの方が高速であることがわかりました。結局のところ、関数内にデータは存在しません // ここでは変更しません。主にアイデアを表現するためです this.historys.push(_.cloneDeep(payload));
    this._currentHistory = this.historys.length - 1;
  }

  @突然変異
  パブリックSET_CURRENT_HISTORY(インデックス: 数値) {
    this._currentHistory = インデックス < 0 ? 0 : インデックス;
  }

  // @Action をやり直す
  パブリック RedoHistory(回数: 数値 = 1) {
    {state、commit} = this.context; とします。
    履歴を: HistoryItem[] = state.historys;
    現在の状態を数値とする。
    (現在 + 回数 >= history.length) の場合、戻り値:
    (times > 0) の間 {
      現在の++;
      history = history[current]とします。
      if (履歴) {
        コミット(history.redo、...history.redoParams、{root: true});
      }
      回--;
    }
    コミット("SET_CURRENT_HISTORY", 現在の);
  }

  // @Actionを元に戻す
  パブリックUndoHistory(回数: 数値 = 1) {
    {state、commit} = this.context; とします。
    履歴を: HistoryItem[] = state.historys;
    現在の状態を数値とする。
    (現在値 - 回数 < 0) の場合は return;
    (times > 0) の間 {
      history = history[current]とします。
      if (履歴) {
        コミット(history.undo、...history.undoParams、{root: true});
      }
      回--;
      現在 - ;
    }
    コミット("SET_CURRENT_HISTORY", 現在の);
  }
}

3. 元に戻す機能とやり直し機能を書く

上記の2つのステップを完了すると、さまざまな操作を記述できます。

データに対する基本的な操作のためのミューテーションを記述する

@突然変異
パブリック CREATE_PAGE(ペイロード: { ページ: PageItem; インデックス: 数値 }) {
  this.pages.splice(payload.index, 0, _.cloneDeep(payload.page));
  this._currentPage = this.pages.length - 1;
}

@突然変異
パブリック REMOVE_PAGE(id: 文字列) {
  index = this.pages.findIndex((p) => p.id == id); とします。
  インデックス > -1 && this.pages.splice(index, 1);
  if (this._currentPage == インデックス) {
    this._currentPage = this.pages.length > 0 ? 0 : -1;
  }
}

必要に応じて、保存->記録->実行というアクションに基本的な操作をカプセル化します。

//パッケージ作成ページ関数@Action
パブリックCreatePage(タイプ: "ページ" | "ダイアログ") {
  {state、commit} = this.context; とします。
  
  // 作成されるページを記録して保存します。let id = _.uniqueId(type) + Date.now();
  pageName = pageType[type]とします。
  ページ: PageItem = {
    id、
    名前: `${pageName}${state.pages.length + 1}`,
    タイプ、
    レイヤー: [],
    スタイル: { 幅: 720, 高さ: 1280 },
  };

  //履歴を作成する let history: HistoryItem = {
    名前: `${pageName} を作成`,
    タイムストラップ: Date.now(),
    やり直し: "ページ/CREATE_PAGE",
    redoParams: [{ index: state.pages.length - 1, page }],
    元に戻す: "ページ/REMOVE_PAGE",
    undoParams: [id],
  };
  // この履歴を保存して記録します commit("Histroy/CREATE_HISTORY", history, { root: true });

  コミット(history.redo、...history.redoParams、{root: true});
}

@アクション
パブリックRemovePage(id: string) {
  // 現場の状況を記録して保存します。let index = this.pages.findIndex((p) => p.id == id);
  if (インデックス < 0) 戻り値:
  ページを作成します: PageItem = this.context.state.pages[index];

  //履歴を作成する let history: HistoryItem = {
    名前: `${page.name} を削除`,
    タイムストラップ: Date.now(),
    やり直し: "ページ/REMOVE_PAGE",
    再実行パラメータ: [id],
    元に戻す: "ページ/CREATE_PAGE",
    undoParams: [{ページ,インデックス}],
  };

  // この履歴レコードを保存します this.context.commit("Histroy/CREATE_HISTORY", history, { root: true });
  this.context.commit(history.redo, ...history.redoParams, { root: true });
}

以上で、元に戻す機能とやり直し機能は基本的に完了です。

4. 使用

1. ページを作成または削除するときに、カプセル化された「アクション」を使用するだけで済みます。

  プライベート作成(タイプ: "ページ" | "ダイアログ") {
    this.$store.dispatch("Page/CreatePage", type);
  }

  プライベート削除(id: 数値) {
    this.$store.dispatch("Page/RemovePage", id);
  }

2. グローバルホットキーを設定する

タイプスクリプトApp.vue

プライベートマウント() {
    自分自身 = this とします。
    ホットキー("ctrl+z", 関数(イベント, ハンドラー) {
      self.$store.dispatch("履歴/元に戻す履歴");
    });
    ホットキー("ctrl+y", 関数(イベント, ハンドラー) {
      self.$store.dispatch("履歴/再実行履歴");
    });
  }

効果

これで、vuex で履歴レコードを実装するためのサンプルコードに関するこの記事は終了です。より関連性の高い vuex 履歴レコードについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • vueでは、前のステップに戻ることは禁止されており、ルートは履歴を保存しません。
  • Vueは入力ボックスに新しい検索履歴機能を実装します

<<:  MySql 8.0.11 のインストール プロセスと Navicat とのリンク時に発生する問題の概要

>>:  DockerでSpring Bootアプリケーションを実行する方法

推薦する

Linuxのファイル操作の知識ポイントを詳しく解説

ファイル操作に関連するシステムコール作成するint creat(const char *ファイル名,...

レスポンシブレイアウトについて知っておくべきこと

1. はじめにレスポンシブ Web デザインにより、Web サイトは複数のデバイスと複数の画面に同時...

HTML でさまざまなスペースの特徴と表現を探る (推奨)

I. 概要HTML テンプレートを作成するときに、テキスト レイアウトの手段としてスペースが使用さ...

Linux で複数の mysql5.7.19 (tar.gz) ファイルをインストールする方法

LinuxでのMySQL-5.7.19バージョンの初心者向けの最初のインストールについては、前の記事...

暗号化における https の Apache 展開の概要

目次目的実験環境実験原理実験手順1. 独立したCAを生成する2. サーバーの秘密鍵と署名要求ファイル...

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

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

MySQL ルートパスワードを変更する 4 つの方法 (要約)

方法1: SET PASSWORDコマンドを使用するまずMySQLにログインします。フォーマット: ...

ウェブページ内でウェブテーブルやdivレイヤーが引き伸ばされる問題の解決策

<br />Web ページをデザインするときには、いつも不快なことに遭遇します。最も一般...

CSS の div の下の同じ行にある複数の要素を右揃えにする

方法1:フロート:右さらに、フローティングにするとレイアウトがよりコンパクトになります(隙間がなくな...

div の特定の実装は自動的に折り返されず、HTML で折り返されないよう強制されます。

1. 改行なしを実現するには<nobr>タグを使用するコードをコピーコードは次のとおりで...

Vueモバイル端末が指のスライド効果を実現

この記事の例では、Vueモバイル端末で指のスライド効果を実現するための具体的なコードを紹介します。具...

vuex名前空間の使用

目次Vuex は単一の状態ツリーを使用するため、すべてのアプリケーション状態が比較的大きなオブジェク...

iframe の多層ネスト、無制限のネスト、高度に適応したソリューション

ページ A、B、C の 3 つがあります。ページ A にはページ B が含まれ、ページ B にはペー...

MySQL の一般的な SQL ステートメントの概要

1. mysqlエクスポートファイル: SELECT `pe2e_user_to_company`....