Автор оригинала: Anthony Gore.
Существует много преимуществ для централизации состояния вашего приложения в магазине Vuex. Одним из преимуществ является то, что вся транзакция записана. Это позволяет для удобных функций, таких как Отладка от времени отладки где вы можете прыгать между предыдущими состояниями, чтобы изолировать проблемы.
В этой статье я продемонстрирую, как создать функцию отмены/повторов с vuex, которая работает аналогично отладке для отладки времени. Эта функция может использоваться в различных сценариях из сложных форм для браузерных игр.
Вы можете проверить завершенный код здесь на Github и попробуй демо в этом Кодепен Отказ Я также создал плагин как модуль NPM под названием Vuex-Undo-Redo Если вы хотите использовать его в проекте.
Примечание: эта статья была первоначально опубликована здесь на блоге разработчиков Vue.js на 2017/11/13.
Настройка плагина
Чтобы сделать эту функцию многоразовой, мы создадим ее как плагин Vue. Эта функция требует, чтобы мы добавили некоторые методы и данные в экземпляр VUE, поэтому мы структурируем плагин в виде микина.
плагин.js.
module.exports = { install(Vue) { Vue.mixin({ // Code goes here }); } };
Чтобы использовать его в проекте, мы можем просто импортировать плагин и установить его:
app.js.
import VuexUndoRedo from './plugin.js'; Vue.use(VuexUndoRedo);
Концепция
Функция будет работать, откатывая последнюю мутацию, если пользователь хочет отменить, затем повторно подавать его, если они хотят повторить. Как мы будем реализовать это?
Подход № 1.
Первый возможный подход состоит в том, чтобы «Снимок» состояния хранилища после каждой мутации и нажимая снимка в массив. Чтобы отменить/повторить мы можем снять правильный снимок и заменить состояние хранилища с ним.
Проблема с таким подходом состоит в том, что состояние хранения является объектом JavaScript. Когда вы нажимаете объект JavaScript в массив, вы просто нажав ссылку на объект. Наивной реализации, как следующее, не будет работать:
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
Подход снимки потребуется, чтобы вы сначала сделали клон состояния перед толканием. Учитывая, что Vue State производится реактивным через автоматические дополнения функций Getter и Setter, он красиво не играет с клонированием.
Подход № 2.
Другим возможным подходом состоит в том, чтобы зарегистрировать каждую преданную мутацию. Чтобы отменить, мы сбрасываем магазин в его начальное состояние, а затем снова запустите мутации; все, кроме последнего. Redoing – это аналогичная концепция.
Учитывая принципы флюса, повторно выполняют мутации из того же начального состояния, чтобы отлично воссоздать состояние. Поскольку это более чистый подход, чем первый, давайте продолжим его.
Регистрация мутаций
Vuex предлагает метод API для подписки на мутации, которые мы можем использовать для их входа. Мы настроим это в Создано
крюк. В обратном вызове мы просто подталкиваем мутацию в массив, который позже может быть повторно запущен.
плагин.js.
Vue.mixin({ data() { return { done: [] } }, created() { this.$store.subscribe(mutation => { this.done.push(mutation); } } });
Метод отменить
Чтобы отменить мутацию, мы рассмотрим магазин, затем повторно запустите все мутации, за исключением последнего. Вот как работает код:
- Используйте
поп
Метод массива для удаления последней мутации - Очистить состояние магазина со специальной мутацией
Just_state
(объясняется ниже) - Итайте каждую оставшуюся мутацию, снова совершайте его в свежий магазин. Обратите внимание, что метод подписки все еще активен во время этого процесса, что означает, что каждая мутация будет продолжать перекреститься. Снимите его снова сразу с
поп
чтобы предотвратить это.
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(); }); } } });
Очистка магазина
Всякий раз, когда этот плагин используется, разработчик должен реализовать мутацию в своем магазине под названием jotedstate
Отказ Это имеет работу по возврату магазина обратно в исходное состояние, чтобы он был готов к повторному построению с нуля.
Разработчик должен сделать это собой, потому что плагин, который мы строят, не имеют доступа к магазину, только экземпляр VUE. Вот пример реализации:
store.js.
new Vuex.Store({ state: { myVal: null }, mutations: { emptyState() { this.replaceState({ myval: null }); } } });
Возвращаясь к нашему плагину, jotedstate
Мутация не должна быть добавлена к нашему сделано
Список, поскольку мы не хотим переоценить, что в процессе отмены. Предотвратите это со следующей логикой:
плагин.js.
Vue.mixin({ data() { ... }, created() { this.$store.subscribe(mutation => { if (mutation.type !== EMPTY_STATE) { this.done.push(mutation); } }); }, methods() { ... } });
Рево метод
Давайте создадим новую недвижимость данных отменить
который будет массивом. Когда мы удаляем последнюю мутацию от сделано
Во время процесса отмены мы нажимаем его на этот массив:
плагин.js.
Vue.mixin({ data() { return { done: [], undone: [] } }, methods: { undo() { this.undone.push(this.done.pop()); ... } } });
Теперь мы можем создать повторять
Метод, который просто примет последнюю мутацию, добавленную в отменить
и повторно совершить это.
Plugins.js.
methods: { undo() { ... }, redo() { let commit = this.undone.pop(); this.$store.commit(`${commit.type}`, commit.payload); } }
Повторить аннулирование
Если пользователь запускает отменить одно или несколько раз, то делает свежий новый коммит, содержание отменить
будет недействительным. Если это произойдет, мы должны пустые отменить
Отказ
Мы можем обнаружить новые коммиты из нашей подписки обратного вызова при добавлении коммита. Логика сложно, хотя, поскольку обратный вызов не имеет никакого очевидного способа познания того, что является новым комминтом, и что такое отказ/реdo.
Самый простой подход – установить флаг NewMutation
в случае. Это будет верно по умолчанию, но методы Undo и Redo будут временно установить его на ложь. Если это установлено значение true, когда передается мутация, Подписаться
Обратный вызов очистит отменить
множество.
плагин.js.
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; } } }); }, }
Основная функциональность теперь завершена! Добавьте плагин в свой собственный проект или на Моя демонстрация Чтобы проверить это.
Общественный API.
В моем демонстрации вы заметите, что кнопки UNDO и REDO отключены всякий раз, когда их функциональность не допускается в данный момент. Например, если бы не было никаких коммитов, вы, очевидно, не можете отменить или повторить. Разработчик, использующий этот плагин, может захотеть реализовать аналогичную функциональность.
Чтобы это позволить этому плагин может предоставить два вычисленных свойства Canoundo
и Canedo
как часть общественного API. Они тривиальны для реализации:
плагин.js.
module.exports = { install(Vue) { Vue.mixin({ data() { ... }, created() { ... }, methods: { ... }, computed: {}, computed: { canRedo() { return this.undone.length; }, canUndo() { return this.done.length; } }; }); }, }
Стать старшим Vue Developer в 2020 году.
Учитесь и осваивайте, какие профессионалы знают о строительстве, тестировании и развертывании, полностью стековых Vue Apps в нашем последнем курсе.
Учить больше