Обычно у вас есть 2 варианта:
Шаблон Memento
- Легко реализовать, во многих случаях он неэффективен.
Додействие применяется, вы делаете снимок текущего состояния и сохраняете его в массив.Этот снимок - Памятка .
Если пользователь хочет отменить, вы просто pop
последний памятку и примените его.Программа возвращается в состояние, в котором она находилась до применения последнего действия.
Этот шаблон ограничен с точки зрения эффективности.Каждый сувенир является относительно большим, поскольку он отражает все текущее состояние.
Но это также проще всего реализовать, поскольку вам не нужно явно кодировать все случаи и их обратные действия, которые вам нужны в шаблоне команд (см. Ниже).
const mementos = []
const input = document.querySelector('input')
function saveMemento() {
mementos.push(input.value)
}
function undo() {
const lastMemento = mementos.pop()
input.value = lastMemento ? lastMemento : input.value
}
<h4> Type some characters and hit Undo </h4>
<input onkeydown="saveMemento()" value="Hello World"/>
<button onclick="undo()">Undo</button>
Шаблон команды
- Сложнее в реализации, но эффективно использует память.
Каждое действиеимеет соответствующее обратное действие (команду).Например, каждый раз, когда вы добавляете символ в текстовое поле, вы сохраняете обратную функцию;который должен удалить символ в этой позиции.
Если пользователь хочет отменить, вы применяете обратное действие.
const commands = []
const input = document.querySelector('input')
function saveCommand(e) {
commands.push({
// the action is also saved for implementing redo, which
// is not implemented in this example.
action: { type: 'add', key: e.key, index: input.selectionStart },
inverse: { type: 'remove', index: input.selectionStart }
})
}
function undo() {
let value = input.value.split('')
const lastCommand = commands.pop()
if (!lastCommand) return
switch (lastCommand.inverse.type) {
case 'remove':
value.splice(lastCommand.inverse.index, 1)
break;
}
input.value = value.join('')
}
<h4> Type some characters and hit Undo </h4>
<input onkeydown="saveCommand(event)" value="Hello World"/>
<button onclick="undo()">Undo</button>
Фрагменты, которые я написал, работают только при добавлении символов, после чего происходит отмена отмены для возврата в состояние до добавления символов, поэтому они упрощают то, какВы должны реализовать это.
Тем не менее я думаю, что они демонстрируют основные концепции обоих шаблонов.
FWIW Я использую UndoManager в своих проектах в качестве стека для моих команд,