在Angular app中撤消重做功能

时间:2018-03-30 08:15:08

标签: angular undo-redo

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

第一个也是最基本的想法是使用一个完全描述app内部的模型,让我们称之为type DataIn struct { Code int `json:"code"` ID string `json:"id"` Data interface{} `json:"data"` } func (s DataIn) toInt() int { switch t := s.Data.(type) case int: i, _ := strings.Atoi(fmt.Sprintf("%v",s.Data)) return i } // using it sampleData := someStruct{ Number1: datain.toInt(), } 。在每个值得记录的更改中,您只需创建一个AppModel的新对象,然后将其推送到堆栈并更新currentIndex。

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

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

AppModel

我能想到的另一个选择是存储执行 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--]; } redo操作的函数调用。这种方法需要我也存储需要调用函数的对象。这些对象可能会被用户删除,因此还必须有一种方法来重新创建对象。当我输入时,这会变得很痛苦:)

您推荐什么方式?

1 个答案:

答案 0 :(得分:1)

这就是为什么建议不要将状态置于单个对象中,而是与每个模块具有适当数量的属性的(业务)模块一起使用的原因。

我建议使用Redux框架(如NGRX或NGXS)进行状态管理。对于NGRX,有一个meta-reducer-library https://www.npmjs.com/package/ngrx-wieder,可以像这样包装您的NGRX reducer:

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)
}

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