这篇文章主要介绍了不可变的。js如何实现撤销重做功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获、下面让小编带着大家一起了解一下。
浏览器的功能越来越强大,许多原来由其他客户端提供的功能渐渐转移到了前端,前端应用也越来越复杂。许多前端应用,尤其是一些在线编辑软件,运行时需要不断处理用户的交互,提供了撤消重做功能来保证交互的流畅性。不过为一个应用实现撤销重做功能并不是一件容易的事情。回来的官方文档中介绍了如何在回家的应用中实现撤销重做功能。基于回家的的撤销功能是一个自顶向下的方案:引入<代码> redux-undo 代码>之后所有的操作都变为了”可撤销的”,然后我们不断修改其配置使得撤销功能变得越来越好用(这也是<代码> redux-undo> 代码有那么多配置项的原因)。
本文将采用自底向上的思路,以一个简易的在线画图工具为例子,使用打印稿,不可变的。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如何实现撤销重做功能