我想在脚本中添加一个undo/redo
函数。我环顾四周,发现了一些建议,其中大多数建议使用command pattern
。
我搜索了例子,教程或其他说明其工作原理的东西,但找不到任何东西。
该函数必须在一页上工作,我的意思是在重新加载该页面之后,该函数必须能够redo/undo
进行最后的思考。
嗯,我不知道命令模式的工作原理,我想创建一个对象,以存储函数的名称,旧值和新值-但我不确定这是否有效做到与否的方法。
也许有人可以给我一个小例子,说明undo/redo
函数的代码应该如何寻找。
答案 0 :(得分:5)
您通常有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>
每个动作都有一个对应的 inverse 动作(命令)。例如,每次在文本框中添加字符时,都会保存反函数;就是删除该位置的字符。
如果用户要撤消操作,则可以应用相反的操作。
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>
我编写的摘录仅在添加字符时起作用,然后单击undo以返回添加字符之前的状态,因此它们过于简化了应如何实现。
尽管如此,我认为它们展示了两种模式的核心概念。
FWIW我在项目中使用UndoManager作为命令堆栈。