Angular应用中的撤消重做功能

san*_*han 7 undo-redo angular

我正在考虑在有角度的应用程序中实现撤消,重做功能的方法。

第一个也是最基本的想法是使用一个完全描述应用程序内部的模型,称之为AppModel。对于每个值得记录的更改,您只需创建一个新对象AppModel并将其推入堆栈并更新currentIndex。

在绝对最坏的情况下,AppModel的对象必须填写500个文本字段,平均长度为20个字符。每次更新就是10000个字符或10kB。

这个数字有多糟?我不认为这是否会导致内存问题,但是否会使每次推送堆栈时应用程序冻结?这是一个基本的实现:

  historyStack: AppModel[];
  currentIndex:number = -1;

  push(newAppModel:AppModel){
    //delete all after current index
    this.historyStack.splice(++this.currentIndex, 0, newAppModel);
  }

  forward(){
    if(this.currentIndex < this.historyStack.length-1){
      this.currentIndex++;
      return this.historyStack[this.currentIndex];
    }
    return this.historyStack[this.currentIndex];
  }
  back(){
    return this.historyStack[this.currentIndex--];
  }
Run Code Online (Sandbox Code Playgroud)

我想到的另一种选择是存储执行redoreverse操作的函数调用。这种方法将需要我还存储哪些对象需要调用函数。用户可能会删除这些对象,因此还必须有一种重新创建对象的方法。当我输入时,这变得很痛苦:)

您推荐什么方式?

Phi*_*hil 3

这就是为什么建议不要将状态放在单个对象中,而是使用(业务)模块,其中每个模块都具有合理数量的属性。

我建议使用 NGRX 或 NGXS 等 Redux 框架进行状态管理。对于 NGRX,有一个元减速器库https://www.npmjs.com/package/ngrx-wieder可以像这样包装您的 NGRX 减速器:

const reducer = (state, action: Actions, listener?: PatchListener) =>
  produce(state, next => {
    switch (action.type) {
      case addTodo.type:
        next.todos.push({id: id(), text: action.text, checked: false})
        return
      case toggleTodo.type:
        const todo = next.todos.find(t => t.id === action.id)
        todo.checked = !todo.checked
        return
      case removeTodo.type:
        next.todos.splice(next.todos.findIndex(t => t.id === action.id), 1)
        return
      case changeMood.type:
        next.mood = action.mood
        return
      default:
        return
    }
}, listener)

const undoableReducer = undoRedo({
  track: true,
  mergeActionTypes: [
    changeMood.type
  ]
})(reducer)

export function appReducer(state = App.initial, action: Actions) {
  return undoableReducer(state, action)
}
Run Code Online (Sandbox Code Playgroud)

这样你就不必一遍又一遍地为每个模块的减速器编写撤消/重做逻辑,只需将其包装在元减速器中即可。并且您可以排除状态中不需要撤消的重部分。您可以在这里找到完整的 Stackblitz 示例,以及实现代码的基本部分(利用 ImmerJS 进行修补):https ://nils-mehlhorn.de/posts/angular-undo-redo-ngrx-redux