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

推薦する

SQLのさまざまな結合サマリーの詳細な説明

SQL 左結合、右結合、内部結合、自然結合 さまざまな結合の概要SQL には、左結合、右結合、内部結...

MySQL 5.7.17 winx64 解凍版のインストールと設定方法のグラフィックチュートリアル

この記事では、MySQL 5.7.17 winx64解凍版のインストールと設定方法を紹介します。具体...

nginxプロセスロックの実装の詳細な説明

目次1. nginxプロセスロックの役割2. エントリーレベルのロックの使用3. nginxプロセス...

JavaScript es6 の新しい配列メソッドの詳細な説明

目次1. 各() 2. arr.filter() 3. arr.every() 4. arr.map...

4種類のMySQL接続とマルチテーブルクエリの詳細な説明

目次MySQL 内部結合、左結合、右結合、外部結合、複数テーブルクエリビルド環境: 1. 内なる慈恩...

純粋な CSS3+DIV で小さな三角形の境界線効果を実現するためのサンプル コード

具体的なコードは次のとおりです。 HTMLコードは次のとおりです <div class=&qu...

Linux での MySQL マルチインスタンスの展開とインストール ガイド

MySQLマルチインスタンスとは簡単に言うと、MySQL マルチインスタンスとは、サーバー上で複数の...

Ubuntu にグラフィック ドライバーが正常にインストールされたかどうかを確認する方法

次のコマンドを実行します: glxinfo | grep レンダリング結果が「はい」の場合、グラフィ...

反応ルーティングでパラメータを渡すいくつかの方法についての簡単な説明

最初のパラメータ渡し方法は、動的ルーティングパラメータ渡しです。リンクのパス属性を設定することで、ル...

VMware 仮想マシンのネットワークの問題の解決方法

目次1. 問題の説明2. 問題解決1. 仮想マシンシステムのインストール時にネットワークがない場合2...

jar パッケージを Docker コンテナに変換する方法

jar パッケージを Docker コンテナに変換する方法1.まずJavaイメージをダウンロードする...

VUE+CanvasはシンプルなGobangゲームの全プロセスを実現します

序文レイアウトの点では、Gobang はランダムな動きを目的とするゲームよりも実装がはるかに簡単で、...

Dockerコマンドは一般ユーザーが実行できるように実装されている

dockerをインストールすると、通常はdockerユーザーグループが作成されます。ステップ2: 現...

Vue の better-scroll コンポーネントを使用して水平スクロール機能を実現する

について最近、Vue を学習する過程で、基本的な知識の練習と強化を目的として、Qunar.com の...

Vue3.0はvue-grid-layoutプラグインを使用してドラッグレイアウトを実装します。

目次1. プラグイン2. 幕間3. 実装4. 検証機能1. プラグインまず、私たちが選んだプラグイン...