溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

怎么用Immutable.js實(shí)現(xiàn)撤銷(xiāo)重做功能

發(fā)布時(shí)間:2022-03-14 15:23:15 來(lái)源:億速云 閱讀:119 作者:iii 欄目:web開(kāi)發(fā)

這篇文章主要介紹了怎么用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 &mdash;&mdash;Add item ${this.newItem.id}&mdash;&mdash; }

}

運(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è)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI