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アプリケーションを実行する方法

推薦する

css n番目から始まるすべての要素を取得する

具体的なコードは次のとおりです。 <div id="ボックス"> &...

HTML の div、td、p およびその他のコンテナーでの強制改行と非改行の実装

1. 改行を強制せず、省略記号で終了します。コードをコピーコードは次のとおりです。 <div ...

CSS 疑似クラス: 空っぽだと光る (サンプルコード)

最近私の記事を読んだ人なら誰でも、私が現在WeChatミニプログラムプロジェクトを担当しており、その...

Expressはログイン認証を実装

この記事では、ログイン認証を実装するためのExpressの具体的なコードを例として紹介します。具体的...

CSS 8 目を引く HOVER 効果のサンプル コード

1. エフェクトHTMLを送信する <div id="送信ボタン">...

Prometheusコンテナのデプロイメントのための実用的なソリューション

環境ホスト名IPアドレス仕えるプロメテウス192.168.237.137プロメテウス、グラファナノー...

MySQL 5.7.16 のインストールと設定方法のグラフィック チュートリアル (Ubuntu 16.04)

Ubuntu 16.04 に MySQL 5.7 をインストールするにはどうすればいいですか?メイ...

Tomcatアーキテクチャの原則をアーキテクチャ設計に分析する

目次1. 学習目標1.1. Tomcatアーキテクチャの設計と原則をマスターして社内スキルを向上させ...

CSS3は三角形の連続拡大効果を実現します

1. CSS3の三角形は特殊効果でズームし続けます11.1 画像プレビュー 11.2 index.h...

MySQL マルチインスタンス構成のアプリケーションシナリオ

目次MySQL 複数インスタンスマルチインスタンスの概要マルチインスタンスとは何ですか?複数のインス...

IDEA が Docker を統合してリモート展開を実現するための詳細な手順

1. Dockerサーバーへのリモートアクセスを有効にするdocker が配置されているリモート サ...

Docker コンテナでネットワーク リクエストが遅くなる問題の解決策

Docker の使用中に、いくつかの問題が発見されました。npm install や bundle ...

DockerでJenkinsをインストールし、初期プラグインのインストール失敗の問題を解決する

Jenkins をインストールした後、プラグインの初期ダウンロードが常に失敗し、インストールが失敗し...

MySQLデータベース最適化技術の簡単な紹介

成熟したデータベース アーキテクチャは、最初から高可用性、高スケーラビリティなどの機能を備えて設計さ...

MySQL DML言語操作例

追加説明、外部キー: 外部キーを使用しないでください。すべての外部キーの概念はアプリケーション層で解...