您好,登錄后才能下訂單哦!
這篇文章主要介紹了怎么用Immutable.js實(shí)現(xiàn)撤銷(xiāo)重做功能的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇怎么用Immutable.js實(shí)現(xiàn)撤銷(xiāo)重做功能文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。
第一步:確定哪些狀態(tài)需要?dú)v史記錄,創(chuàng)建自定義的 State 類(lèi)
并非所有的狀態(tài)都需要?dú)v史記錄。許多狀態(tài)是非?,嵥榈?,尤其是一些與鼠標(biāo)或者鍵盤(pán)交互相關(guān)的狀態(tài),例如在畫(huà)圖工具中拖拽一個(gè)圖形時(shí)我們需要設(shè)置一個(gè)「正在進(jìn)行拖拽」的標(biāo)記,頁(yè)面會(huì)根據(jù)該標(biāo)記顯示對(duì)應(yīng)的拖拽提示,顯然該拖拽標(biāo)記不應(yīng)該出現(xiàn)在歷史記錄中;而另一些狀態(tài)無(wú)法被撤銷(xiāo)或是不需要被撤銷(xiāo),例如網(wǎng)頁(yè)窗口大小,向后臺(tái)發(fā)送過(guò)的請(qǐng)求列表等。
排除那些不需要?dú)v史記錄的狀態(tài),我們將剩下的狀態(tài)用 Immutable Record 封裝起來(lái),并定義 State 類(lèi):
// State.ts
import { Record, List, Set } from 'immutable'
const StateRecord = Record({
items: List<Item>
transform: d3.ZoomTransform
selection: number
})
// 用類(lèi)封裝,便于書(shū)寫(xiě) TypeScript,注意這里最好使用Immutable 4.0 以上的版本
export default class State extends StateRecord {}
這里我們的例子是一個(gè)簡(jiǎn)易的在線畫(huà)圖工具,所以上面的 State 類(lèi)中包含了三個(gè)字段,items 用來(lái)記錄已經(jīng)繪制的圖形,transform 用來(lái)記錄畫(huà)板的平移和縮放狀態(tài),selection 則表示目前選中的圖形的 ID。而畫(huà)圖工具中的其他狀態(tài),例如圖形繪制預(yù)覽,自動(dòng)對(duì)齊配置,操作提示文本等,則沒(méi)有放在 State 類(lèi)中。
第二步:定義 Action 基類(lèi),并為每種不同的操作創(chuàng)建對(duì)應(yīng)的 Action 子類(lèi)
與 redux-undo 不同的是,我們?nèi)匀徊捎妹钅J剑憾x基類(lèi) Action,所有對(duì) State 的操作都被封裝為一個(gè) Action 的實(shí)例;定義若干 Action 的子類(lèi),對(duì)應(yīng)于不同類(lèi)型的操作。
在 TypeScript 中,Action 基類(lèi)用 Abstract Class 來(lái)定義比較方便。
// 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 方法用來(lái)計(jì)算「下一個(gè)狀態(tài)」,prev 方法用來(lái)計(jì)算「上一個(gè)狀態(tài)」。getMessage 方法用來(lái)獲取 Action 對(duì)象的簡(jiǎn)短描述。通過(guò) getMessage 方法,我們可以將用戶(hù)的操作記錄顯示在頁(yè)面上,讓用戶(hù)更方便地了解最近發(fā)生了什么。prepare 方法用來(lái)在 Action 第一次被應(yīng)用之前,使其「準(zhǔn)備好」,AppHistory 的定義在本文后面會(huì)給出。
Action 子類(lèi)舉例
下面的 AddItemAction 是一個(gè)典型的 Action 子類(lèi),用于表達(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)選中該圖形,為了使得撤銷(xiāo)該操作時(shí) state.selection 變?yōu)樵瓉?lái)的值
// 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í),用戶(hù)交互產(chǎn)生一個(gè) Action 流,每次產(chǎn)生 Action 對(duì)象時(shí),我們調(diào)用該對(duì)象的 next 方法來(lái)計(jì)算后一個(gè)狀態(tài),然后將該 action 保存到一個(gè)列表中以備后用;用戶(hù)進(jìn)行撤銷(xiāo)操作時(shí),我們從 action 列表中取出最近一個(gè) Action 并調(diào)用其 prev 方法。應(yīng)用運(yùn)行時(shí),next/prev 方法被調(diào)用的情況大致如下:
// initState 是一開(kāi)始就給定的應(yīng)用初始狀態(tài)
// 某一時(shí)刻,用戶(hù)交互產(chǎn)生了 action1 ...
state1 = action1.next(initState)
// 又一個(gè)時(shí)刻,用戶(hù)交互產(chǎn)生了 action2 ...
state2 = action2.next(state1)
// 同樣的,action3也出現(xiàn)了 ...
state3 = action3.next(state2)
// 用戶(hù)進(jìn)行撤銷(xiāo),此時(shí)我們需要調(diào)用最近一個(gè)action的prev方法
state4 = action3.prev(state3)
// 如果再次進(jìn)行撤銷(xiāo),我們從action列表中取出對(duì)應(yīng)的action,調(diào)用其prev方法
state5 = action2.prev(state4)
// 重做的時(shí)候,取出最近一個(gè)被撤銷(xiāo)的action,調(diào)用其next方法
state6 = action2.next(state5)
Applied-Action
為了方便后面的說(shuō)明,我們對(duì) Applied-Action 進(jìn)行一個(gè)簡(jiǎn)單的定義: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)撤銷(xiāo)重做功能”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“怎么用Immutable.js實(shí)現(xiàn)撤銷(xiāo)重做功能”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。