
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({
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 = [];
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:
- Verwenden Sie die
pop
Array-Methode, um die letzte Mutation zu entfernen. - Löschen Sie den Speicherstatus mit der speziellen Mutation
EMPTY_STATE
( EMPTY_STATE
unten). - 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; } }, }); }, }