這篇文章主要介紹了怎么用Immutable.js實(shí)現(xiàn)撤銷重做功能的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇怎么用Immutable.js實(shí)現(xiàn)撤銷重做功能文章都會(huì)有所收獲,下面我們一起來看看吧。
成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供臨渭區(qū)網(wǎng)站建設(shè)、臨渭區(qū)做網(wǎng)站、臨渭區(qū)網(wǎng)站設(shè)計(jì)、臨渭區(qū)網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、臨渭區(qū)企業(yè)網(wǎng)站模板建站服務(wù),10年臨渭區(qū)做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
第一步:確定哪些狀態(tài)需要?dú)v史記錄,創(chuàng)建自定義的 State 類
并非所有的狀態(tài)都需要?dú)v史記錄。許多狀態(tài)是非?,嵥榈模绕涫且恍┡c鼠標(biāo)或者鍵盤交互相關(guān)的狀態(tài),例如在畫圖工具中拖拽一個(gè)圖形時(shí)我們需要設(shè)置一個(gè)「正在進(jìn)行拖拽」的標(biāo)記,頁面會(huì)根據(jù)該標(biāo)記顯示對(duì)應(yīng)的拖拽提示,顯然該拖拽標(biāo)記不應(yīng)該出現(xiàn)在歷史記錄中;而另一些狀態(tài)無法被撤銷或是不需要被撤銷,例如網(wǎng)頁窗口大小,向后臺(tái)發(fā)送過的請(qǐng)求列表等。
排除那些不需要?dú)v史記錄的狀態(tài),我們將剩下的狀態(tài)用 Immutable Record 封裝起來,并定義 State 類:
// State.ts
import { Record, List, Set } from 'immutable'
const StateRecord = Record({
items: List
transform: d3.ZoomTransform
selection: number
})
// 用類封裝,便于書寫 TypeScript,注意這里最好使用Immutable 4.0 以上的版本
export default class State extends StateRecord {}
這里我們的例子是一個(gè)簡易的在線畫圖工具,所以上面的 State 類中包含了三個(gè)字段,items 用來記錄已經(jīng)繪制的圖形,transform 用來記錄畫板的平移和縮放狀態(tài),selection 則表示目前選中的圖形的 ID。而畫圖工具中的其他狀態(tài),例如圖形繪制預(yù)覽,自動(dòng)對(duì)齊配置,操作提示文本等,則沒有放在 State 類中。
第二步:定義 Action 基類,并為每種不同的操作創(chuàng)建對(duì)應(yīng)的 Action 子類
與 redux-undo 不同的是,我們?nèi)匀徊捎妹钅J剑憾x基類 Action,所有對(duì) State 的操作都被封裝為一個(gè) Action 的實(shí)例;定義若干 Action 的子類,對(duì)應(yīng)于不同類型的操作。
在 TypeScript 中,Action 基類用 Abstract Class 來定義比較方便。
// actions/index.ts
export default abstract class Action {
abstract next(state: State): State
abstract prev(state: State): State
prepare(appHistory: AppHistory): AppHistory { return appHistory }
getMessage() { return this.constructor.name }
}
Action 對(duì)象的 next 方法用來計(jì)算「下一個(gè)狀態(tài)」,prev 方法用來計(jì)算「上一個(gè)狀態(tài)」。getMessage 方法用來獲取 Action 對(duì)象的簡短描述。通過 getMessage 方法,我們可以將用戶的操作記錄顯示在頁面上,讓用戶更方便地了解最近發(fā)生了什么。prepare 方法用來在 Action 第一次被應(yīng)用之前,使其「準(zhǔn)備好」,AppHistory 的定義在本文后面會(huì)給出。
Action 子類舉例
下面的 AddItemAction 是一個(gè)典型的 Action 子類,用于表達(dá)「添加一個(gè)新的圖形」。
// actions/AddItemAction.ts
export default class AddItemAction extends Action {
newItem: Item
prevSelection: number
constructor(newItem: Item) {
super()
this.newItem = newItem
}
prepare(history: AppHistory) {
// 創(chuàng)建新的圖形后會(huì)自動(dòng)選中該圖形,為了使得撤銷該操作時(shí) state.selection 變?yōu)樵瓉淼闹?/p>
// prepare 方法中讀取了「添加圖形之前 selection 的值」并保存到 this.prevSelection
this.prevSelection = history.state.selection
return history
}
next(state: State) {
return state
.setIn(['items', this.newItem.id], this.newItem)
.set('selection', this.newItemId)
}
prev(state: State) {
return state
.deleteIn(['items', this.newItem.id])
.set('selection', this.prevSelection)
}
getMessage() { return ——Add item ${this.newItem.id}—— }
}
運(yùn)行時(shí)行為
應(yīng)用運(yùn)行時(shí),用戶交互產(chǎn)生一個(gè) Action 流,每次產(chǎn)生 Action 對(duì)象時(shí),我們調(diào)用該對(duì)象的 next 方法來計(jì)算后一個(gè)狀態(tài),然后將該 action 保存到一個(gè)列表中以備后用;用戶進(jìn)行撤銷操作時(shí),我們從 action 列表中取出最近一個(gè) Action 并調(diào)用其 prev 方法。應(yīng)用運(yùn)行時(shí),next/prev 方法被調(diào)用的情況大致如下:
// initState 是一開始就給定的應(yīng)用初始狀態(tài)
// 某一時(shí)刻,用戶交互產(chǎn)生了 action1 ...
state1 = action1.next(initState)
// 又一個(gè)時(shí)刻,用戶交互產(chǎn)生了 action2 ...
state2 = action2.next(state1)
// 同樣的,action3也出現(xiàn)了 ...
state3 = action3.next(state2)
// 用戶進(jìn)行撤銷,此時(shí)我們需要調(diào)用最近一個(gè)action的prev方法
state4 = action3.prev(state3)
// 如果再次進(jìn)行撤銷,我們從action列表中取出對(duì)應(yīng)的action,調(diào)用其prev方法
state5 = action2.prev(state4)
// 重做的時(shí)候,取出最近一個(gè)被撤銷的action,調(diào)用其next方法
state6 = action2.next(state5)
Applied-Action
為了方便后面的說明,我們對(duì) Applied-Action 進(jìn)行一個(gè)簡單的定義:Applied-Action 是指那些操作結(jié)果已經(jīng)反映在當(dāng)前應(yīng)用狀態(tài)中的 action;當(dāng) action 的 next 方法執(zhí)行時(shí),該 action 變?yōu)?applied;當(dāng) prev 方法被執(zhí)行時(shí),該 action 變?yōu)?unapplied。
關(guān)于“怎么用Immutable.js實(shí)現(xiàn)撤銷重做功能”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“怎么用Immutable.js實(shí)現(xiàn)撤銷重做功能”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。