Immutable.js如何实现撤销重做功能

  

这篇文章主要介绍了不可变的。js如何实现撤销重做功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获、下面让小编带着大家一起了解一下。

浏览器的功能越来越强大,许多原来由其他客户端提供的功能渐渐转移到了前端,前端应用也越来越复杂。许多前端应用,尤其是一些在线编辑软件,运行时需要不断处理用户的交互,提供了撤消重做功能来保证交互的流畅性。不过为一个应用实现撤销重做功能并不是一件容易的事情。回来的官方文档中介绍了如何在回家的应用中实现撤销重做功能。基于回家的的撤销功能是一个自顶向下的方案:引入<代码> redux-undo 之后所有的操作都变为了”可撤销的”,然后我们不断修改其配置使得撤销功能变得越来越好用(这也是<代码> redux-undo>

本文将采用自底向上的思路,以一个简易的在线画图工具为例子,使用打印稿,不可变的。js实现一个实用的“撤消重做“功能。大致效果如下图所示:

不可变的。js如何实现撤销重做功能

<强>第一步:确定哪些状态需要历史记录,创建自定义的状态类

并非所有的状态都需要历史记录。许多状态是非常琐碎的,尤其是一些与鼠标或者键盘交互相关的状态,例如在画图工具中拖拽一个图形时我们需要设置一个“正在进行拖拽”的标记,页面会根据该标记显示对应的拖拽提示,显然该拖拽标记不应该出现在历史记录中;而另一些状态无法被撤销或是不需要被撤销,例如网页窗口大小,向后台发送过的请求列表等。

排除那些不需要历史记录的状态,我们将剩下的状态用不变的记录封装起来,并定义州类:

//, State.ts   import {,记录,列表,Set },得到& # 39;不可变# 39;   const  StateRecord =,记录({   ,项目:List   ,变换:d3.ZoomTransform   ,选择:号码   })//,用类封装,便于书写,打印稿,注意这里最好使用Immutable  4.0,以上的版本   export  default  class  State  extends  StateRecord  {}

这里我们的例子是一个简易的在线画图工具,所以上面类的状态中包含了三个字段,用物品来记录已经绘制的图形,变换用来记录画板的平移和缩放状态,选择则表示目前选中的图形的ID。而画图工具中的其他状态,例如图形绘制预览,自动对齐配置,操作提示文本等,则没有放在状态类中。

<强>第二步:定义行动基类,并为每种不同的操作创建对应的行动子类

与redux-undo不同的是,我们仍然采用命令模式:定义基类行动,所有对国家的操作都被封装为一个行动的实例;定义若干行动的子类,对应于不同类型的操作。

在打字稿中,行动基类用抽象类来定义比较方便。

//,/index.ts行动   export  default  abstract  class  Action  {   接下来,abstract (状态:状态):状态   ,abstract 上一页(状态:状态):状态   ,准备(appHistory: appHistory):, AppHistory  {, return  AppHistory }   ,getMessage () {, return  this.constructor.name }   }

操作对象的下方法用来计算”下一个状态”,上一页方法用来计算”上一个状态”.getMessage方法用来获取行动对象的简短描述。通过getMessage方法,我们可以将用户的操作记录显示在页面上,让用户更方便地了解最近发生了什么.prepare方法用来在行动第一次被应用之前,使其“准备好”,AppHistory的定义在本文后面会给出。

<强>操作子类举例

下面的AddItemAction是一个典型的行动子类,用于表达“添加一个新的图形”。

//,/AddItemAction.ts行动   export  default  class  AddItemAction  extends  Action  {   ,newItem:项目   ,prevSelection:号码   ,构造函数(newItem:项目),{   ,super ()=,this.newItem  newItem   ,}   ,准备(历史:,AppHistory), {   ,//创建新的图形后会自动选中该图形,为了使得撤销该操作时,state.selection 变为原来的值   ,//prepare 方法中读取了“添加图形之前,selection 的值”并保存到,this.prevSelection=,this.prevSelection  history.state.selection   return 历史   ,}   接下来,(状态:状态),{   return 状态   .setIn才能([& # 39;项目# 39;,,this.newItem.id],, this.newItem)   这里才能(& # 39;选择# 39;,,this.newItemId)   ,}   ,上一页(状态:状态),{   return 状态   .deleteIn才能([& # 39;项目# 39;,,this.newItem.id])   这里才能(& # 39;选择# 39;,,this.prevSelection)   ,}   ,getMessage () {, return “Add  item  $ {this.newItem.id}”,}   }

Immutable.js如何实现撤销重做功能