Erstellen des Vuex Undo / Redo Plugins für VueJS

Bild


Die Zentralisierung des Status Ihrer Anwendung im Vuex Store bietet viele Vorteile. Ein Vorteil ist, dass alle Transaktionen erfasst werden. Auf diese Weise können Sie praktische Funktionen wie das Laufzeit-Debugging verwenden , mit denen Sie zwischen vorherigen Status wechseln können, um Aufgaben von der Ausführung zu trennen.


In diesem Artikel werde ich zeigen, wie Sie die Funktion "Rückgängig / Wiederherstellen" mit Vuex für Rollback / Return erstellen. Dies funktioniert ähnlich wie das Debuggen während des Debuggens. Diese Funktion kann in einer Vielzahl von Szenarien verwendet werden, von komplexen Formen bis zu browserbasierten Spielen.


Sie können den fertigen Code hier auf Github überprüfen und die Demo in diesem Codepen ausprobieren . Ich habe auch ein Plugin als NPM-Modul namens vuex-undo-redo erstellt, wenn Sie es in einem Projekt verwenden möchten.


Hinweis: Dieser Artikel wurde ursprünglich hier im Entwicklerblog von Vue.js 2017/11/13 veröffentlicht.

Plugin Konfiguration


Um diese Funktion wiederverwendbar zu machen, erstellen wir sie als Vue-Plugin. Für diese Funktion müssen wir der Vue-Instanz einige Methoden und Daten hinzufügen, damit wir das Plugin als Mixin strukturieren können.


module.exports = { install(Vue) { Vue.mixin({ // Code goes here }); } }; 

Um es in einem Projekt zu verwenden, können wir einfach das Plugin importieren und verbinden:


 import VuexUndoRedo from './plugin.js'; Vue.use(VuexUndoRedo); 

Idee


Die Funktion funktioniert, indem die letzte Mutation zurückgesetzt wird, wenn der Benutzer sie abbrechen möchte, und sie dann erneut angewendet wird, wenn er sie wiederholen möchte. Wie machen wir das?


Ansatz Nr. 1


Der erste mögliche Ansatz besteht darin, nach jeder Mutation „Snapshots“ des Status des Repositorys zu erstellen und den Snapshot in einem Array zu platzieren. Zum Rückgängigmachen / Wiederherstellen können wir den richtigen Snapshot abrufen und durch den Speicherstatus ersetzen.


Das Problem bei diesem Ansatz ist, dass der Status des Repositorys ein JavaScript-Objekt ist. Wenn Sie ein JavaScript-Objekt in ein Array einfügen, geben Sie einfach einen Verweis auf das Objekt ein. Eine naive Implementierung wie die folgende funktioniert nicht:


 var state = { ... }; var snapshot = []; // Push the first state snapshot.push(state); // Push the second state state.val = "new val"; snapshot.push(state); // Both snapshots are simply a reference to state console.log(snapshot[0] === snapshot[1]); // true 

Für den Snapshot-Ansatz müssen Sie vor dem Push zunächst einen Statusklon erstellen. Da der Status von Vue durch automatisches Hinzufügen der Funktionen get und set reaktiv wird, funktioniert das Klonen nicht besonders gut.


Ansatz Nr. 2


Ein anderer möglicher Ansatz besteht darin, jede feste Mutation zu registrieren. Zum Abbrechen setzen wir den Speicher auf den Ausgangszustand zurück und führen die Mutationen erneut aus. alle bis auf den letzten. Rückerstattung ähnliches Konzept.


Angesichts der Prinzipien von Flux sollte ein Neustart von Mutationen aus demselben Ausgangszustand den Zustand idealerweise wiederherstellen. Da dies ein sauberer Ansatz als der erste ist, fahren wir fort.


Registrierung von Mutationen


Vuex bietet eine API-Methode zum Abonnieren von Mutationen an, mit der wir sie registrieren können. Wir werden dies auf den created Hook setzen. Im Rückruf fügen wir die Mutation einfach in ein Array ein, das später erneut ausgeführt werden kann.


 Vue.mixin({ data() { return { done: [] } }, created() { this.$store.subscribe(mutation => { this.done.push(mutation); } } }); 

Rollback-Methode


Um die Mutation abzubrechen, löschen wir das Repository und führen dann alle Mutationen außer der letzten erneut aus. So funktioniert der Code:


  1. Verwenden Sie die pop Array-Methode, um die letzte Mutation zu entfernen.
  2. Löschen Sie den Speicherstatus mit der speziellen Mutation EMPTY_STATE ( EMPTY_STATE unten).
  3. Wiederholen Sie jede verbleibende Mutation und korrigieren Sie sie erneut im neuen Speicher. Bitte beachten Sie, dass die Abonnementmethode während dieses Vorgangs noch aktiv ist, dh jede Mutation wird erneut hinzugefügt. Löschen Sie es sofort mit pop .

 const EMPTY_STATE = 'emptyState'; Vue.mixin({ data() { ... }, created() { ... }, methods() { undo() { this.done.pop(); this.$store.commit(EMPTY_STATE); this.done.forEach(mutation => { this.$store.commit(`${mutation.type}`, mutation.payload); this.done.pop(); }); } } }); 

Reinigungsgeschäft


Wann immer dieses Plugin verwendet wird, muss der Entwickler eine Mutation in seinem Repository namens emptyState implementieren. Die Herausforderung besteht darin, den Speicher wieder in seinen ursprünglichen Zustand zu versetzen, damit er von Grund auf wiederhergestellt werden kann.


Der Entwickler muss dies selbst tun, da das von uns erstellte Plugin keinen Zugriff auf den Store hat, sondern nur auf die Vue-Instanz. Hier ist eine Beispielimplementierung:


 new Vuex.Store({ state: { myVal: null }, mutations: { emptyState() { this.replaceState({ myval: null }); } } }); 

Zurück zu unserem Plugin sollte die emptyState Mutation nicht zu unserer Liste " emptyState hinzugefügt werden, da wir dies während des Rollback-Prozesses nicht erneut emptyState möchten. Verhindern Sie dies mit der folgenden Logik:


 Vue.mixin({ data() { ... }, created() { this.$store.subscribe(mutation => { if (mutation.type !== EMPTY_STATE) { this.done.push(mutation); } }); }, methods() { ... } }); 

Rückgabemethode


Erstellen wir eine neue Dateneigenschaft, die undone wird und ein Array ist. Wenn wir die letzte Mutation entfernen, die während des Rollback-Prozesses ausgeführt wurde, fügen wir sie in dieses Array ein:


 Vue.mixin({ data() { return { done: [], undone: [] } }, methods: { undo() { this.undone.push(this.done.pop()); ... } } }); 

Jetzt können wir eine redo erstellen, die einfach die zuletzt hinzugefügte undone Mutation nimmt und sie erneut festschreibt.


 methods: { undo() { ... }, redo() { let commit = this.undone.pop(); this.$store.commit(`${commit.type}`, commit.payload); } } 

Keine Rückgabe möglich


Wenn der Benutzer die Stornierung ein- oder mehrmals initiiert und dann ein neues Commit ausführt, wird der Inhalt von undone ungültig. In diesem Fall müssen wir das undone leeren.


Beim Hinzufügen eines Commits können wir neue Commits aus unserem Abonnement-Rückruf ermitteln. Die Logik ist jedoch schwierig, da der Rückruf keine offensichtliche Möglichkeit bietet, herauszufinden, was ein neues Commit ist und was Rückgängig / Wiederherstellen ist.


Am einfachsten ist es, das Flag newMutation zu setzen. Es ist standardmäßig true, aber Rollback- und Return-Methoden setzen es vorübergehend auf false. Wenn die Mutation auf true gesetzt ist, löscht der subscribe Rückruf das undone Array.


 module.exports = { install(Vue) { Vue.mixin({ data() { return { done: [], undone: [], newMutation: true }; }, created() { this.$store.subscribe(mutation => { if (mutation.type !== EMPTY_STATE) { this.done.push(mutation); } if (this.newMutation) { this.undone = []; } }); }, methods: { redo() { let commit = this.undone.pop(); this.newMutation = false; this.$store.commit(`${commit.type}`, commit.payload); this.newMutation = true; }, undo() { this.undone.push(this.done.pop()); this.newMutation = false; this.$store.commit(EMPTY_STATE); this.done.forEach(mutation => { this.$store.commit(`${mutation.type}`, mutation.payload); this.done.pop(); }); this.newMutation = true; } } }); }, } 

Die Hauptfunktionalität ist jetzt abgeschlossen! Fügen Sie das Plugin Ihrem eigenen Projekt oder meiner Demo hinzu , um es zu testen.


Öffentliche API


In meiner Demo werden Sie feststellen, dass die Schaltflächen Abbrechen und Zurück deaktiviert sind, wenn ihre Funktionalität derzeit nicht möglich ist. Wenn beispielsweise noch keine Commits vorhanden waren, können Sie diese offensichtlich nicht abbrechen oder wiederholen. Ein Entwickler, der dieses Plugin verwendet, möchte möglicherweise ähnliche Funktionen implementieren.


Um dies zu aktivieren, kann das Plugin zwei berechnete Eigenschaften, canUndo und canRedo als Teil der öffentlichen API bereitstellen. Dies ist trivial zu implementieren:


 module.exports = { install(Vue) { Vue.mixin({ data() { ... }, created() { ... }, methods: { ... }, computed: {}, computed: { canRedo() { return this.undone.length; }, canUndo() { return this.done.length; } }, }); }, } 

Source: https://habr.com/ru/post/de433986/


All Articles